應用mysql_udf與curl庫完成http_post通訊模塊示例。本站提示廣大學習愛好者:(應用mysql_udf與curl庫完成http_post通訊模塊示例)文章只能為提供參考,不一定能成為您想要的結果。以下是應用mysql_udf與curl庫完成http_post通訊模塊示例正文
應用mysql_udf與curl庫完成http_post通訊模塊(mysql_udf,multi_curl,http,post)
這個模塊其今朝重要用於xoyo江湖的sns與kingsoft_xoyo自立研發的TCSQL數據庫做數據同步,當有feed拔出sns數據庫,應用觸 發器挪用該模塊,向tcsql數據庫發送同步數據。也能夠應用該模塊與其它應用socket接口的數據庫或法式做轉發與同步。
http_post模塊重要應用mysql_udf接口,與curl庫兩部門技巧。
mysql_udf是mysql為c說話供給的一個接口,經由過程這個接口,用戶可以自界說mysql的函數,經由過程挪用這些mysql函數,挪用響應的c說話 模塊來履行特定功效,完成mysql數據與內部運用的交互。curl庫是一個比擬經常使用的運用層收集協定庫,重要用到的是個中的curl_multi異步通 信api,用來停止收集傳輸。
起首參考mysql官方供給的udf_example.c文件,樹立3個重要的接口函數,分離是初始化函數,履行函數與析構函數。
//args是sql語句傳回的參數,message是前往失足信息應用這些都是劃定好的。
my_bool http_post_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
//主函數體
longlong http_post(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error);
//析構函數體
void http_post_deinit(UDF_INIT *initid);
//args是sql語句傳回的參數,message是前往失足信息,應用這些都是劃定好的。
//初始化函數體 my_bool http_post_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
//主函數體 longlong http_post(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error);
//析構函數體 void http_post_deinit(UDF_INIT *initid);
在mysql_udf接口中,主函數體中是不許可應用new或malloc靜態分派內存,所以假如須要請求內存空間,必需用xxxx_init()函數申 請並將請求的地址賦給initid->ptr指針,然後在主函數體中應用,並在xxxx_deinit析構函數體中釋放。別的關於 mysql_udf接口的挪用似乎當並發量跨越必定水平,假如是應用靜態分派內存,會湧現double free的毛病,為了不這個毛病,所以在我的法式裡應用靜態空間與靜態請求空間相聯合的方法,如許假如數據較小,並發量較年夜,不會湧現double free毛病。關於靜態請求空間,最年夜約在160000~170000byte閣下,我這裡應用的160000,當mysql傳送的數據年夜於這個數的時 候,才靜態請求內存。初始化函數體以下:
my_bool http_post_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 2)
{
strcpy(message,"Wrong arguments to http_post; ");
return 1;
}
if(args->arg_count == 2 && args->args[1]!=NULL)
{
int flexibleLength = strlen(args->args[1]);
if(flexibleLength > 160000)
{
int allocLength = 200 + flexibleLength;
if (!(initid->ptr=(char*) malloc(allocLength) ) )
{
strcpy(message,"Couldn't allocate memory in http_post_init");
return 1;
}
return 0;
}
else
{
initid->ptr=NULL;
}
}
return 0;
}
個中http_post_init須要前往my_bool型。這個函數量的是給用戶供給一個方法,磨練由mysql參數傳出去的數據能否准確,假如准確則 前往0,則mysql會主動挪用界說的主函數,假如前往1,則mysql打印message信息加入,不會挪用主函數。所以在設定前往值的時刻必定留意。
主函數以下:
longlong http_post( UDF_INIT *initid, UDF_ARGS *args,
char *is_null __attribute__((unused)),
char *error __attribute__((unused)))
{
char* sendBuffer=NULL;
CURL *curl;
CURLM *multi_handle;
int still_running;
int times=0;//try times if select false
int TRY_TIMES=25;
struct timeval timeout;//set a suitable timeout to play around with
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
char sendArray[160000] = "\0";//can not move this into the if
if(initid->ptr == NULL)
{
//char sendArray[160000] = "\0";//error
sendBuffer=sendArray;
}
else
{
sendBuffer = initid->ptr;
TRY_TIMES=100;
}
strcpy(sendBuffer,args->args[1]);
curl = curl_easy_init();
multi_handle = curl_multi_init();
if(curl && multi_handle)
{
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL,args->args[0]);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,sendBuffer);
curl_multi_add_handle(multi_handle, curl);
while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle,\ &still_running));
while(still_running && times< TRY_TIMES)
{
int rc; //select() return code
int maxfd;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep); //get file descriptors from the transfers
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep,\ &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc)
{
case -1://select error
break;
case 0:
default: // timeout
while(CURLM_CALL_MULTI_PERFORM !== curl_multi_perform(multi_handle, &still_running));
break;
}
times++;
}//end while
curl_multi_remove_handle(multi_handle,curl);
curl_multi_cleanup(multi_handle);//always cleanup
curl_easy_cleanup(curl);
if(times>=TRY_TIMES)
{
return 1;
}
return 0;
}//end if
return 1;
}
在主函數中,重要應用curl庫停止通訊,curl庫分紅3部門,easy是同步形式,multi是異步形式,share形式是多線程同享數據的形式。
關於easy發送完數據後,會壅塞期待辦事器的response,假如沒 有前往,就會一向壅塞,固然可以設置一個timeout,但假如這個時光設小了,easy發送年夜數據的時刻就會中止,設太年夜了影響時光效力,別的當吸收端 不發送response的時刻,easy庫即便發送完了數據,也會壅塞期待,有些時刻關於發送端來說不須要期待吸收真個respons,當發送終了便可以 停止了,這個時刻easy就不實用。所以最初選擇multi庫。
如法式所示,起首得初始化,並設置easy句柄為post形式,指定須要post的數據,以下:
curl = curl_easy_init();
multi_handle = curl_multi_init();
curl_easy_setopt(curl, CURLOPT_URL,args->args[0]);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,sendBuffer);
因為要應用multi形式,必需也要初始化一個easy形式,並將這個easy形式的句柄放入所謂的multi函數履行棧:
curl_multi_add_handle(multi_handle, curl);
應用curl_multi_perform(multi_handle, &still_running),來停止異步傳輸,但假如該函數前往的不是CURLM_CALL_MULTI_PERFORM,則須要從新履行。直到輪回while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));停止。此時假如適才函數體中的still_running被置為1,注解銜接樹立,正在發送數據。須要合營select機制來停止數據發送。
函數 curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);會將最年夜的描寫符寫入maxfd,
然後用select停止期待:rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
最初假如select前往值不為-1(error)0(timeout)時刻再次停止異步傳輸,即履行curl_multi_perform函數,直到
still_running為0,法式停止加入。
這裡設置了一個最年夜履行次數的限制,假如辦事器湧現了成績,不克不及發送response,則still_running不會變成0,法式會逝世輪回,
所以,設置一個最年夜輪回次數TRY_TIMES,避免這類情形產生。然則這個次數設小了,數據能夠沒有發送完,就加入了,如設置太年夜了,法式發送完了,辦事器沒有response就會多履行過剩輪回。所以這個TRY_TIMES須要依據數據的年夜小和收集狀態來設置,比正常
傳輸數據的次數略長。這裡我小數據的時刻輪回設次數25,年夜數據輪回設為100.
最初是析構函數體:
void http_post_deinit(UDF_INIT *initid)
{
if (initid!=NULL && initid->ptr!=NULL)
{
free(initid->ptr);
initid->ptr = NULL;
}
}
將初始化函數設置的內存釋放。
編譯履行進程以下:
將法式保留為http_post.c編譯以下(請依據機械上的mysql途徑停止調劑):
gcc -wall -I/usr/local/webserver/mysql/include/mysql/ -shared http_post.c -o http_post.so -fPIC
//應用mysql供給的頭文件生成靜態鏈接庫
cp -f http_post.so /usr/local/webserver/mysql/lib/mysql/plugin/http_post.so
//將生成的.so文件放入mysql的plugin文件夾下
//進入mysql對靜態鏈接庫中的函數停止裝置
cd /usr/local/webserver/mysql/bin/mysql
./mysql
//在mysql敕令行下輸出以下敕令:
mysql> DROP FUNCTION IF EXISTS http_post;
//其目標是假如體系內裝置了同名函數先輩性drop。
mysql> CREATE FUNCTION http_post RETURNS INTEGER SONAME ‘http_post.so';
//生成http_post函數,並指明挪用起源是http_post.so。
//最初挪用函數,其目標是向指定ip和端口發送post數據。挪用前先翻開指定ip主機上的收集調試助手,並監聽3888端。
mysql> select http_post(‘testpost.com/index.php','sfasfa');
在收集助手中可以看到以下成果: