程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> 應用mysql_udf與curl庫完成http_post通訊模塊示例

應用mysql_udf與curl庫完成http_post通訊模塊示例

編輯:MySQL綜合教程

應用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');

在收集助手中可以看到以下成果:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved