《MYSQL教程使用mysql_udf與curl庫(kù)完成http_post通信模塊示例》要點(diǎn):
本文介紹了MYSQL教程使用mysql_udf與curl庫(kù)完成http_post通信模塊示例,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
使用mysql_udf與curl庫(kù)完成http_post通信模塊(mysql_udf,multi_curl,http,post)MYSQL教程
這個(gè)模塊其目前主要用于xoyo江湖的sns與kingsoft_xoyo自主研發(fā)的TCSQL數(shù)據(jù)庫(kù)做數(shù)據(jù)同步,當(dāng)有feed插入sns數(shù)據(jù)庫(kù),使用觸 發(fā)器調(diào)用該模塊,向tcsql數(shù)據(jù)庫(kù)發(fā)送同步數(shù)據(jù).也可以使用該模塊與其它使用socket接口的數(shù)據(jù)庫(kù)或程序做轉(zhuǎn)發(fā)與同步.
http_post模塊主要使用mysql_udf接口,與curl庫(kù)兩部分技術(shù).
mysql_udf是mysql為c語(yǔ)言提供的一個(gè)接口,通過(guò)這個(gè)接口,用戶(hù)可以自定義mysql的函數(shù),通過(guò)調(diào)用這些mysql函數(shù),調(diào)用相應(yīng)的c語(yǔ)言 模塊來(lái)執(zhí)行特定功能,實(shí)現(xiàn)mysql數(shù)據(jù)與外部應(yīng)用的交互.curl庫(kù)是一個(gè)比較常用的應(yīng)用層網(wǎng)絡(luò)協(xié)議庫(kù),主要用到的是其中的curl_multi異步通 信api,用來(lái)進(jìn)行網(wǎng)絡(luò)傳輸.
首先參考mysql官方提供的udf_example.c文件,建立3個(gè)主要的接口函數(shù),分別是初始化函數(shù),執(zhí)行函數(shù)與析構(gòu)函數(shù).MYSQL教程
在mysql_udf接口中,主函數(shù)體中是不允許使用new或malloc動(dòng)態(tài)分配內(nèi)存,所以如果需要申請(qǐng)內(nèi)存空間,必須用xxxx_init()函數(shù)申 請(qǐng)并將申請(qǐng)的地址賦給initid->ptr指針,然后在主函數(shù)體中使用,并在xxxx_deinit析構(gòu)函數(shù)體中釋放.另外對(duì)于 mysql_udf接口的調(diào)用好像當(dāng)并發(fā)量超過(guò)一定程度,如果是使用動(dòng)態(tài)分配內(nèi)存,會(huì)出現(xiàn)double free的錯(cuò)誤,為了避免這個(gè)錯(cuò)誤,所以在我的程序里使用靜態(tài)空間與動(dòng)態(tài)申請(qǐng)空間相結(jié)合的方式,這樣如果數(shù)據(jù)較小,并發(fā)量較大,不會(huì)出現(xiàn)double free錯(cuò)誤.對(duì)于靜態(tài)申請(qǐng)空間,最大約在160000~170000byte左右,我這里使用的160000,當(dāng)mysql傳送的數(shù)據(jù)大于這個(gè)數(shù)的時(shí) 候,才動(dòng)態(tài)申請(qǐng)內(nèi)存.初始化函數(shù)體如下:MYSQL教程
????? if(args->arg_count == 2 && args->args[1]!=NULL)
????? {
??????????? int flexibleLength = strlen(args->args[1]);? MYSQL教程
??????? 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;
??????? }? MYSQL教程
????? }
?????? return 0;? MYSQL教程
??? }
MYSQL教程
主函數(shù)如下:MYSQL教程
??? 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;
??? }? MYSQL教程
??? 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;
}
MYSQL教程
對(duì)于easy發(fā)送完數(shù)據(jù)后,會(huì)阻塞等待服務(wù)器的response,如果沒(méi) 有返回,就會(huì)一直阻塞,當(dāng)然可以設(shè)置一個(gè)timeout,但如果這個(gè)時(shí)間設(shè)小了,easy發(fā)送大數(shù)據(jù)的時(shí)候就會(huì)中斷,設(shè)太大了影響時(shí)間效率,另外當(dāng)接收端 不發(fā)送response的時(shí)候,easy庫(kù)即使發(fā)送完了數(shù)據(jù),也會(huì)阻塞等待,有些時(shí)候?qū)τ诎l(fā)送端來(lái)講不需要等待接收端的respons,當(dāng)發(fā)送完畢就可以 結(jié)束了,這個(gè)時(shí)候easy就不適用.所以最后選擇multi庫(kù).MYSQL教程
如程序所示,首先得初始化,并設(shè)置easy句柄為post模式,指定需要post的數(shù)據(jù),如下:MYSQL教程
curl = curl_easy_init();MYSQL教程
multi_handle = curl_multi_init();MYSQL教程
curl_easy_setopt(curl, CURLOPT_URL,args->args[0]);MYSQL教程
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);MYSQL教程
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,sendBuffer);MYSQL教程
由于要使用multi模式,必須也要初始化一個(gè)easy模式,并將這個(gè)easy模式的句柄放入所謂的multi函數(shù)執(zhí)行棧:MYSQL教程
curl_multi_add_handle(multi_handle, curl);MYSQL教程
使用curl_multi_perform(multi_handle, &still_running),來(lái)進(jìn)行異步傳輸,但如果該函數(shù)返回的不是CURLM_CALL_MULTI_PERFORM,則需要重新執(zhí)行.直到循環(huán)while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));結(jié)束.此時(shí)如果剛才函數(shù)體中的still_running被置為1,表明連接建立,正在發(fā)送數(shù)據(jù).需要配合select機(jī)制來(lái)進(jìn)行數(shù)據(jù)發(fā)送.MYSQL教程
函數(shù) curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);會(huì)將最大的描述符寫(xiě)入maxfd,MYSQL教程
然后用select進(jìn)行等待:rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);MYSQL教程
最后如果select返回值不為-1(error)0(timeout)時(shí)候再次進(jìn)行異步傳輸,即執(zhí)行curl_multi_perform函數(shù),直到MYSQL教程
still_running為0,程序結(jié)束退出.MYSQL教程
這里設(shè)置了一個(gè)最大執(zhí)行次數(shù)的限制,如果服務(wù)器出現(xiàn)了問(wèn)題,不能發(fā)送response,則still_running不會(huì)變?yōu)?,程序會(huì)死循環(huán),MYSQL教程
所以,設(shè)置一個(gè)最大循環(huán)次數(shù)TRY_TIMES,防止這種情況發(fā)生.但是這個(gè)次數(shù)設(shè)小了,數(shù)據(jù)可能沒(méi)有發(fā)送完,就退出了,如設(shè)置太大了,程序發(fā)送完了,服務(wù)器沒(méi)有response就會(huì)多執(zhí)行多余循環(huán).所以這個(gè)TRY_TIMES需要根據(jù)數(shù)據(jù)的大小和網(wǎng)絡(luò)狀況來(lái)設(shè)置,比正常MYSQL教程
傳輸數(shù)據(jù)的次數(shù)略長(zhǎng).這里我小數(shù)據(jù)的時(shí)候循環(huán)設(shè)次數(shù)25,大數(shù)據(jù)循環(huán)設(shè)為100.MYSQL教程
最后是析構(gòu)函數(shù)體:MYSQL教程
編譯執(zhí)行過(guò)程如下:MYSQL教程
將程序保存為http_post.c編譯如下(請(qǐng)根據(jù)機(jī)器上的mysql路徑進(jìn)行調(diào)整):
MYSQL教程
在網(wǎng)絡(luò)助手中可以看到如下結(jié)果:MYSQL教程
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/6381.html