前几天在自己的私服中用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