前幾天在自己的私服中用c寫了一個模擬股市系統,所使用的數據是通過socket發送HTTP請求,然後獲得新浪財經的接口頁面進行處理。那麼現在我們把需求和需要做的事情總結一下:
1、如何發送HTTP請求
2、請求到某個股票網站的輸入和輸出分別是什麼
3、處理收到的字符串數據
先試著寫一個簡單的HTTP請求發送和接收程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<netdb.h> int main(int argc,char *argv[]) { char urlstr[8096]; char buf[8096]; struct hostent *server; //創建套接字 int fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) printf("sockett err:%m\n"),exit(-1); printf("socket ok!\n"); struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_port=htons(80); //解析域名 server = gethostbyname("hq.sinajs.cn"); //連接 memcpy((char *)&addr.sin_addr.s_addr,(char*)server->h_addr, server->h_length); int r=connect(fd,(struct sockaddr*)&addr,sizeof addr); if(r==-1) printf("connect err:%m\n"),exit(-1); printf("connect ok!\n"); //發送HTTP請求 sprintf(urlstr,"GET /?list=sh600000 HTTP/1.1\r\nHost: hq.sinajs.cn\r\nConnection: Close\r\n\r\n"); write(fd,urlstr,strlen(urlstr)); //接收並打印 r=recv(fd,buf,8096,0); if(r<=0) {close(fd);return -1;} buf[r]=0; printf("%s",buf); //關閉套接字 close(fd); return 0; } |
上面的例子使用非阻塞的recv作為接收,優點是接收後不會阻塞的運行程序進行接下來的輸出打印,而缺點是如果返回的頁面數據很多,分包之後會發現recv接收的頁面是不全的,只有大概2k多數據。所以在實際應用中我使用了read作為接收函數。
我的需求是通過上證股票代碼獲得開盤收盤和當前價格等信息,已知新浪股票的HTTP接口用法是這樣 http://hq.sinajs.cn/?list=sh600000,sh600406 放到瀏覽器一看就明白了,已經滿足通過代碼獲的所有信息,接下來寫具體的處理過程。
下面是我所寫的通過股票代碼獲得實時價格的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
#include<iostream> #include<sstream> #include<string.h> #include<time.h> #include<stdlib.h> #include<unistd.h> #include<mysql/mysql.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<netdb.h> using namespace std; int s_num = 5; char stock[][10]={"000001","600000","600005","600006","600007"}; // 上證指數,浦發銀行,武鋼股份,東風汽車,中國國貿 int main(int argc,char *argv[]) { time_t tval; struct tm *now; tval = time(NULL); now = localtime(&tval); char str[1024]; int i; double d; int i1; char ch; MYSQL my_connection; MYSQL_RES *result; MYSQL_ROW row; mysql_init(&my_connection); struct hostent *server; stringstream sstr,recvstr; char strss[1024]; char zd[33][50]; int fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) printf("sockett err:%m\n"),exit(-1); printf("socket ok!\n"); struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_port=htons(80); server = gethostbyname("hq.sinajs.cn"); memcpy((char *)&addr.sin_addr.s_addr,(char*)server->h_addr, server->h_length); int r=connect(fd,(struct sockaddr*)&addr,sizeof addr); if(r==-1) printf("connect err:%m\n"),exit(-1); printf("connect ok!\n"); //同時獲得多個個股信息 sstr << "GET /?list="; for (i=0; i<s_num; i++) { sstr << "sh"; sstr << stock[i]; if (i != s_num-1) sstr << ","; } sstr << " HTTP/1.1\r\nHost: hq.sinajs.cn\r\nConnection: Close\r\n\r\n"; cout << "debug:" << sstr.str(); write(fd,sstr.str().c_str(),sstr.str().length()); //阻塞read一直讀取直到fd被超時關閉 while(read(fd,&ch,1)) { recvstr << ch; } close(fd); cout << recvstr.str() << endl; //因為本人習慣於使用stream類型保存便於以後getline和處理 if (mysql_real_connect(&my_connection, "0.0.0.0","user", "passwd", "datadb", 0, NULL, 0)) { printf("[%04d%02d%02d%02d%02d%02d] Connection success\n",now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); } else { printf("[%04d%02d%02d%02d%02d%02d] Connection failed\n",now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); return -1; } recvstr.getline(strss, 1024); i = 0; while(!recvstr.eof()&&!recvstr.fail()) { if((strstr(strss,"var hq_str_sh") != NULL) && (strstr(strss,stock[i]) != NULL)) { //======數據庫處理過程已省略====== //======數據庫處理過程已省略====== i++; } if (i == s_num) break; memset(strss, 0x00, 1024); recvstr.getline(strss, 1024); } mysql_close(&my_connection); return 0; } |
由於涉及自己伺服器數據庫的數據結構,數據庫處理過程已經省略。getline得到的每一行可以用sscanf分隔成字符串,然後再使用atof轉化為價格數的浮點。引號內的字段可以分別保存到zd[33][50]的二位數組中,關於新浪的股票接口,它們每個字段表示的意義大概如下:
0股票名稱;1今開價;2昨收價;3當前價;4今最高;5今最低;……最後是30更新日期和31時間
自用程序寫的比較爛,如有缺陷歡迎指正。
=======
kujou_rin