1. 利用 CURLOPT_WRITEFUNCTION 設置回調函數, 利用 CURLOPT_WRITEDATA 獲取數據指針
官網文檔以下
javascript
CALLBACK OPTIONS
CURLOPT_WRITEFUNCTION css
Pass a pointer to a function that matches the following prototype: size_t function( char *ptr, size_t size, size_t nmemb, void *userdata); This function gets called by libcurl as soon as there is data received that needs to be saved. The size of the data pointed to by ptr is size multiplied with nmemb, it will not be zero terminated. Return the number of bytes actually taken care of. If that amount differs from the amount passed to your function, it'll signal an error to the library. This will abort the transfer and return CURLE_WRITE_ERROR. html
From 7.18.0, the function can return CURL_WRITEFUNC_PAUSE which then will cause writing to this connection to become paused. See curl_easy_pause(3) for further details. java
This function may be called with zero bytes data if the transferred file is empty. linux
Set this option to NULL to get the internal default function. The internal default function will write the data to the FILE * given with CURLOPT_WRITEDATA. 程序員
Set the userdata argument with the CURLOPT_WRITEDATA option. app
The callback function will be passed as much data as possible in all invokes, but you cannot possibly make any assumptions. It may be one byte, it may be thousands. The maximum amount of body data that can be passed to the write callback is defined in the curl.h header file: CURL_MAX_WRITE_SIZE (the usual default is 16K). If you however have CURLOPT_HEADER set, which sends header data to the write callback, you can get up to CURL_MAX_HTTP_HEADER bytes of header data passed into it. This usually means 100K. curl
CURLOPT_WRITEDATA 函數
Data pointer to pass to the file write function. If you use the CURLOPT_WRITEFUNCTION option, this is the pointer you'll get as input. If you don't use a callback, you must pass a 'FILE *' (cast to 'void *') as libcurl will pass this to fwrite() when writing data. By default, the value of this parameter is unspecified. this
The internal CURLOPT_WRITEFUNCTION will write the data to the FILE * given with this option, or to stdout if this option hasn't been set.
If you're using libcurl as a win32 DLL, you MUST use the CURLOPT_WRITEFUNCTION if you set this option or you will experience crashes.
This option is also known with the older name CURLOPT_FILE, the name CURLOPT_WRITEDATA was introduced in 7.9.7.
2. 完整代碼以下:
- /*------------------------------------------------------------------------------------------
- 名稱: http_sina_curl_callbak.c
- 功能: 利用libcurl的回調機制實現sina股票接口. http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
- http://hq.sinajs.cn/list=sz150013
- http://hq.sinajs.cn/list=sh601318
- #libcurl的調試信息
- * About to connect() to hq.sinajs.cn port 80 (#0)
- * Trying 219.142.78.242...
- * connected
- * Connected to hq.sinajs.cn (219.142.78.242) port 80 (#0)
- > GET /list=sz150001 HTTP/1.1
- Host: hq.sinajs.cn
- Accept: * *
- < HTTP/1.1 200 OK
- < Cache-Control: no-cache
- < Content-Length: 250
- < Connection: Keep-Alive
- < Content-Type: application/x-javascript; charset=GBK
- <
- * Connection #0 to host hq.sinajs.cn left intact
- * Closing connection #0
- #運行結果:
- root@OpenWrt:/xutest# ./http_sina_stock
- sz150001: dq = 0.724, jg = 0.730, jd = 0.722, jk = 0.729
- sz150013: dq = 0.886, jg = 0.893, jd = 0.885, jk = 0.889
- sz150100: dq = 0.981, jg = 0.982, jd = 0.979, jk = 0.980
- sz150152: dq = 0.964, jg = 0.967, jd = 0.964, jk = 0.965
- sz150018: dq = 0.958, jg = 0.960, jd = 0.957, jk = 0.960
- root@OpenWrt:/xutest#
- -------------------------------------------------------------------------------------------*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <curl/curl.h>
- #include <assert.h>
- #define HTTP_GET "GET"
- #define HTTP_PUT "PUT"
- #define HTTP_HEAD "HEAD"
- #define HTTP_POST "POST"
- #define HTTP_DELETE "DELETE"
- #define HTTP_RET_OK "HTTP/1.1 200 OK\r\n"
- #define SINA_HOST "hq.sinajs.cn"
- #define SINA_PORT 80
- #define ARRAY_COUNT(x) (sizeof(x) / sizeof(x[0]))
- typedef struct {
- float price_dq; //當前價, 取拼音的首字母
- float price_zs; //昨收價
- float price_jk; //今開價
- float price_jg; //今高價
- float price_jd; //今低價
- } stock_info_t;
- #define DBG //printf
- #define CURL_DBG (0) //1=開啓curl的調試
- //-----------------------------------------------------------------------------------------
- static void delay_ms(int msec)
- {
- struct timeval timeout;
- memset(&timeout, 0, sizeof(struct timeval));
- timeout.tv_sec = msec / 1000;
- timeout.tv_usec = (msec % 1000) * 1000;
- select(0, NULL, NULL, NULL, &timeout);
- }
- size_t callback_get_head(void *ptr, size_t size, size_t nmemb, void *userp)
- {
- strcat(userp, ptr);
- return size * nmemb; //必須返回這個大小, 不然只回調一次
- }
- static char connect_cloud(char *pc_ret, const char *host_addr, const int portno,
- const char *pc_method, struct curl_slist *http_headers)
- {
- CURL *curl;
- CURLcode res = CURLE_GOT_NOTHING;
- assert((pc_ret != NULL) && (host_addr != NULL) && (pc_method != NULL));
- //curl_global_init(CURL_GLOBAL_DEFAULT);
- curl = curl_easy_init();
- if (!curl) {
- fprintf(stderr, "--- curl init Error!\n");
- return 0;
- }
- curl_easy_setopt(curl, CURLOPT_URL, host_addr);
- curl_easy_setopt(curl, CURL_HTTP_VERSION_1_1, 1L); //HTTP 1.1
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); //設置超時, 單位爲秒.
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); //屏蔽其它信號, makes libcurl NOT ask the system to ignore SIGPIPE signals
- curl_easy_setopt(curl, CURLOPT_HEADER, 1L); //下載數據包括HTTP頭部, The default value for this parameter is 0.
- //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); //The default value for this parameter is 1
- #if (CURL_DBG == 1)
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //調試用: 顯示交互明細,
- //curl_easy_setopt(curl, CURLOPT_HEADER, 1L); //調試用: 只顯示頭行的返回
- #endif
- #if 1
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, pc_method);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback_get_head); //下載數據的回調函數
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, pc_ret); //下載數據的指針
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers); //多行的HTTP頭部
- #endif
- res = curl_easy_perform(curl);
- if(res != CURLE_OK)
- fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
- curl_easy_cleanup(curl);
- return 1;
- }
- int sina_get_stock(char *pc_ret, const char *pc_stockid)
- {
- char pc_url[200], ret;
- //組織請求頭部, 自動末尾添加'\r\n'
- struct curl_slist *http_headers = NULL;
- http_headers = curl_slist_append(http_headers, "Accept: */*");
- //http_headers = curl_slist_append(http_headers, "Connection: Close");
- //發送請求, 再判斷返回值
- //url = hq.sinajs.cn/list=sz150013
- sprintf(pc_url, "%s/list=%s", SINA_HOST, pc_stockid);
- ret = connect_cloud(pc_ret, pc_url, SINA_PORT, HTTP_GET, http_headers);
- //DBG("cloud ret = %s\n", pc_ret);
- //釋放 http_headers資源
- curl_slist_free_all(http_headers);
- return(ret);
- }
- #if 0
- /*字符串不一樣含義的數據用逗號隔開了,按照程序員的思路,順序號從0開始。
- 0:」大秦鐵路」,股票名字;
- 1:」27.55″,今日開盤價;
- 2:」27.25″,昨日收盤價;
- 3:」26.91″,當前價格;
- 4:」27.55″,今日最高價;
- 5:」26.20″,今日最低價;
- 6:」26.91″,競買價,即「買一」報價;
- 7:」26.92″,競賣價,即「賣一」報價;
- 8:」22114263″,成交的股票數,因爲股票交易以一百股爲基本單位,因此在使用時,一般把該值除以一百;
- 9:」589824680″,成交金額,單位爲「元」,爲了一目瞭然,一般以「萬元」爲成交金額的單位,因此一般把該值除以一萬;
- 10:」4695″,「買一」申請4695股,即47手;
- 11:」26.91″,「買一」報價;
- 12:」57590″,「買二」
- 13:」26.90″,「買二」
- 14:」14700″,「買三」
- 15:」26.89″,「買三」
- 16:」14300″,「買四」
- 17:」26.88″,「買四」
- 18:」15100″,「買五」
- 19:」26.87″,「買五」
- 20:」3100″,「賣一」申報3100股,即31手;
- 21:」26.92″,「賣一」報價
- (22, 23), (24, 25), (26,27), (28, 29)分別爲「賣二」至「賣四的狀況」
- 30:」2008-01-11″,日期;
- 31:」15:05:32″,時間;*/
- #endif
- void stock_parse(stock_info_t *stock, const char *pc_data)
- {
- char *pc_str, *pc_str1;
- int i;
- assert((stock != NULL) &&(pc_data != NULL));
- //DBG("data = %s\n", pc_data);
- pc_str = strstr(pc_data, HTTP_RET_OK);
- if (pc_str) {
- pc_str += strlen(HTTP_RET_OK);
- pc_str = strstr(pc_str, "\r\n\r\n");
- pc_str += 4;
- DBG("valid str = %s\n", pc_str);
- //解析數據, var hq_str_sz150013="???B,0.899,0.906,0.897,0.903,0.895,0.897,0.898,9739979,8751058.780,2200,0.897,143548,0.896,572900,0.895,625300,0.894,167300,0.893,9800,0.898,60000,0.899,362300,0.900,162500,0.901,217000,0.902,2013-11-06,10:38:44,00";
- pc_str = strchr(pc_str, ',');
- pc_str ++;
- for (i=0; i<5; i++) {
- pc_str1 = strchr(pc_str, ',');
- if (pc_str1) {
- *pc_str1 = '\0';
- switch(i) {
- case 0: stock->price_jk = atof(pc_str); break; //今開
- case 1: stock->price_zs = atof(pc_str); break; //昨收
- case 2: stock->price_dq = atof(pc_str); break; //當前
- case 3: stock->price_jg = atof(pc_str); break; //今高
- case 4: stock->price_jd = atof(pc_str); break; //今低
- }
- pc_str = pc_str1 + 1; //指向下個有效數據
- }
- else break;
- }
- }
- }
- //-------------------------------------------------------------------------------
- int main(void)
- {
- char pc_ret[1000];
- int i, max;
- stock_info_t stock;
- char *stock_array[] = {"sz150001", "sz150013", "sz150100", "sz150152", "sz150018"}; //改爲本身的
- max = ARRAY_COUNT(stock_array);
- for(i=0; i<max; i++) {
- memset(pc_ret, 0x00, sizeof(pc_ret));
- sina_get_stock(pc_ret, stock_array[i]);
- DBG("sina ret OK = %s\n", pc_ret);
- stock_parse(&stock, pc_ret);
- printf("%s: dq = %.3f, jg = %.3f, jd = %.3f, jk = %.3f\n",
- stock_array[i], stock.price_dq, stock.price_jg, stock.price_jd ,stock.price_jk);
- }
- return 1;
- }
3. Makefile:
- OPENWRT = 1
- ifeq ($(OPENWRT), 1)
- CC = ~/OpenWrt-SDK-ar71xx-for-linux-i486-gcc-4.6-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc
- CFLAGS += -I ~/openwrt-lib/include -L ~/openwrt-lib/lib
- LFLAGS += -lcurl -lcrypto -lz -lssl
- else
- CC = gcc
- LFLAGS += -lcurl
- endif
- CFLAGS += -Wall -O2
- #CFLAGS += -g
- #可執行文件名和相關的obj文件
- APP_BINARY = http_sina_stock
- SRCS += http_sina_curl_callback.c
- OBJS = $(SRCS:.c=.o)
- all: APP_FILE
- APP_FILE: $(OBJS)
- $(CC) $(CFLAGS) $(OBJS) -o $(APP_BINARY) $(LFLAGS)
- .PHONY: clean
- clean:
- @echo "cleanning project"
- $(RM) *.a $(OBJS) *~ *.so *.lo $(APP_BINARY)
- @echo "clean completed"
4. openwrt下運行結果以下root@OpenWrt:/xutest# ./http_sina_stocksz150001: dq = 0.724, jg = 0.730, jd = 0.722, jk = 0.729sz150013: dq = 0.886, jg = 0.893, jd = 0.885, jk = 0.889sz150100: dq = 0.981, jg = 0.982, jd = 0.979, jk = 0.980sz150152: dq = 0.964, jg = 0.967, jd = 0.964, jk = 0.965sz150018: dq = 0.958, jg = 0.960, jd = 0.957, jk = 0.960root@OpenWrt:/xutest#