日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

HTTP_POST———使用mysql_udf与curl库完成http_post通信模块(mysql_udf,multi_curl,http,post)...

發(fā)布時間:2023/12/19 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HTTP_POST———使用mysql_udf与curl库完成http_post通信模块(mysql_udf,multi_curl,http,post)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

HTTP_POST———使用mysql_udf與curl庫完成http_post通信模塊(mysql_udf,multi_curl,http,post)

這個模塊其目前主要用于xoyo江湖的sns與kingsoft_xoyo自主研發(fā)的TCSQL數(shù)據(jù)庫做數(shù)據(jù)同步,當(dāng)有feed插入sns數(shù)據(jù)庫,使用觸 發(fā)器調(diào)用該模塊,向tcsql數(shù)據(jù)庫發(fā)送同步數(shù)據(jù)。也可以使用該模塊與其它使用socket接口的數(shù)據(jù)庫或程序做轉(zhuǎn)發(fā)與同步。

??? http_post模塊主要使用mysql_udf接口,與curl庫兩部分技術(shù)。

??? mysql_udf是mysql為c語言提供的一個接口,通過這個接口,用戶可以自定義mysql的函數(shù),通過調(diào)用這些mysql函數(shù),調(diào)用相應(yīng)的c語言 模塊來執(zhí)行特定功能,實現(xiàn)mysql數(shù)據(jù)與外部應(yīng)用的交互。curl庫是一個比較常用的應(yīng)用層網(wǎng)絡(luò)協(xié)議庫,主要用到的是其中的curl_multi異步通 信api,用來進行網(wǎng)絡(luò)傳輸。

??? 首先參考mysql官方提供的udf_example.c文件,建立3個主要的接口函數(shù),分別是初始化函數(shù),執(zhí)行函數(shù)與析構(gòu)函數(shù)。

  • //args是sql語句傳回的參數(shù),message是返回出錯信息使用這些都是規(guī)定好的。??
  • my_bool?http_post_init(UDF_INIT?*initid,?UDF_ARGS?*args,?char?*message);??
  • //主函數(shù)體??
  • longlong?http_post(UDF_INIT?*initid,?UDF_ARGS?*args,?char?*is_null,char?*error);??
  • //析構(gòu)函數(shù)體??
  • void?http_post_deinit(UDF_INIT?*initid);??
  • //args 是sql語句傳回的參數(shù),message是返回出錯信息使用這些都是規(guī)定好的。 my_bool http_post_init(UDF_INIT *initid, UDF_ARGS *args, char *message); //主函數(shù)體 longlong http_post(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error); //析構(gòu)函數(shù)體 void http_post_deinit(UDF_INIT *initid); ?

    ???

    ???? 在mysql_udf接口中,主函數(shù)體中是不允許使用new或melloc動態(tài)分配內(nèi)存,所以如果需要申請內(nèi)存空間,必須用xxxx_init()函數(shù)申 請并將申請的地址賦給initid->ptr指針,然后在主函數(shù)體中使用,并在xxxx_deinit析構(gòu)函數(shù)體中釋放。另外對于 mysql_udf接口的調(diào)用好像當(dāng)并發(fā)量超過一定程度,如果是使用動態(tài)分配內(nèi)存,會出現(xiàn)double free的錯誤,為了避免這個錯誤,所以在我的程序里使用靜態(tài)空間與動態(tài)申請空間相結(jié)合的方式,這樣如果數(shù)據(jù)較小,并發(fā)量較大,不會出現(xiàn)double free錯誤。對于靜態(tài)申請空間,最大約在160000~170000byte左右,我這里使用的160000,當(dāng)mysql傳送的數(shù)據(jù)大于這個數(shù)的時 候,才動態(tài)申請內(nèi)存。初始化函數(shù)體如下:

  • 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型。這個函數(shù)目的是給用戶提供一個方式,檢驗由mysql參數(shù)傳進來的數(shù)據(jù)是否正確,如果正確則 返回0,則mysql會自動調(diào)用定義的主函數(shù),如果返回1,則mysql打印message信息退出,不會調(diào)用主函數(shù)。所以在設(shè)定返回值的時候一定注意。

    ??? 主函數(shù)如下:

  • 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;??
  • }??????
  • ??????? 在主函數(shù)中,主要使用curl庫進行通信,curl庫分成3部分,easy是同步模式,multi是異步模式,share模式是多線程共享數(shù)據(jù)的模式。

    對 于easy發(fā)送完數(shù)據(jù)后,會阻塞等待服務(wù)器的response,如果沒 有返回,就會一直阻塞,當(dāng)然可以設(shè)置一個timeout,但如果這個時間設(shè)小了,easy發(fā)送大數(shù)據(jù)的時候就會中斷,設(shè)太大了影響時間效率,另外當(dāng)接收端 不發(fā)送response的時候,easy庫即使發(fā)送完了數(shù)據(jù),也會阻塞等待,有些時候?qū)τ诎l(fā)送端來講不需要等待接收端的respons,當(dāng)發(fā)送完畢就可以 結(jié)束了,這個時候easy就不適用。所以最后選擇multi庫。

    如程序所示,首先得初始化,并設(shè)置easy句柄為post模式,指定需要post的數(shù)據(jù),如下:

    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函數(shù)執(zhí)行棧:

    curl_multi_add_handle(multi_handle, curl);

    使用curl_multi_perform(multi_handle, &still_running),來進行異步傳輸,但如果該函數(shù)返回的不是CURLM_CALL_MULTI_PERFORM,則需要重新執(zhí)行。直到循環(huán)

    while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));結(jié)束。

    此時如果剛才函數(shù)體中的still_running被置為1,表明連接建立,正在發(fā)送數(shù)據(jù)。需要配合select機制來進行數(shù)據(jù)

    發(fā)送。

    函數(shù)???curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);會將最大的描述符寫入maxfd,

    然后用select進行等待:rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);

    最后如果select返回值不為-1(error)0(timeout)時候再次進行異步傳輸,即執(zhí)行curl_multi_perform函數(shù),直到still_running為0,程序結(jié)束退出。

    這里設(shè)置了一個最大執(zhí)行次數(shù)的限制,如果服務(wù)器出現(xiàn)了問題,不能發(fā)送response,則still_running不會變?yōu)?,程序會死循環(huán),

    所以,設(shè)置一個最大循環(huán)次數(shù)TRY_TIMES,防止這種情況發(fā)生。但是這個次數(shù)設(shè)小了,數(shù)據(jù)可能沒有發(fā)送完,就退出了,如設(shè)置太大了,程序發(fā)送完了,服務(wù)器沒有response就會多執(zhí)行多余循環(huán)。所以這個TRY_TIMES需要根據(jù)數(shù)據(jù)的大小和網(wǎng)絡(luò)狀況來設(shè)置,比正常

    傳輸數(shù)據(jù)的次數(shù)略長。這里我小數(shù)據(jù)的時候循環(huán)設(shè)次數(shù)25,大數(shù)據(jù)循環(huán)設(shè)為100.

    最后是析構(gòu)函數(shù)體:

  • void?http_post_deinit(UDF_INIT?*initid)??
  • {??
  • ?????if?(initid!=NULL?&&?initid->ptr!=NULL)??
  • ????????{??
  • ????????????free(initid->ptr);??
  • ????????????initid->ptr?=?NULL;??
  • ????????}??
  • ??
  • }??
  • ?將初始化函數(shù)設(shè)置的內(nèi)存釋放。

    編譯執(zhí)行過程如下:

    /將程序保存為http_post.c編譯如下(請根據(jù)機器上的mysql路徑進行調(diào)整):
    gcc -wall -I/usr/local/webserver/mysql/include/mysql/ -shared http_post.c -o http_post.so -fPIC

    //使用mysql提供的頭文件生成動態(tài)鏈接庫
    cp -f http_post.so /usr/local/webserver/mysql/lib/mysql/plugin/http_post.so

    //將生成的.so文件放入mysql的plugin文件夾下

    //進入mysql對動態(tài)鏈接庫中的函數(shù)進行安裝
    cd /usr/local/webserver/mysql/bin/mysql
    ./mysql
    //在mysql命令行下輸入如下命令:
    mysql> DROP FUNCTION IF EXISTS http_post;
    //其目的是如果系統(tǒng)內(nèi)安裝了同名函數(shù)先進性drop。
    mysql> CREATE FUNCTION http_post RETURNS INTEGER SONAME 'http_post.so';
    //生成http_post函數(shù),并指明調(diào)用來源是http_post.so。

    //最后調(diào)用函數(shù),其目的是向指定ip和端口發(fā)送post數(shù)據(jù)。調(diào)用前先打開指定ip主機上的網(wǎng)絡(luò)調(diào)試助手,并監(jiān)聽3888端口。
    mysql> select http_post('testpost.com/index.php','sfasfa');

    在網(wǎng)絡(luò)助手中可以看到如下結(jié)果:

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的HTTP_POST———使用mysql_udf与curl库完成http_post通信模块(mysql_udf,multi_curl,http,post)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。