socket为什么里面的recv一个字节一个字节读取 与 多个字节读取得到的结果为什么不正确?
C语言利用socket获取网上资源时候 ,为什么里面的recv一个字节一个字节读取与多个字节读取得到的结构为什么不正确?有人能回答吗?在下面代码里面已经表明地方了就是 #1 和 #2 两个地方,希望对这方面比较了解的朋友能解答一下。
下面这段程序是通过socket来下载百度里面的图标图片,为什么recv单个字节接收能够接收到图片,而多个字节接收却报错呢,使用的编译器是windows平台下的MinGW,g++ 4.7
/* * ===================================================================================== * * Filename: GetTheHtml.cpp * * Description: On Windows ,use the socket to get host's html or img * * Version: 1.0 * Created: 2012/10/9 19:25:52 * Revision: none * Compiler: gcc * Author: UnGeek * Email: ungeek5201314@gmail.com * * ===================================================================================== */#include <windows.h>#include <winsock2.h>#include <iostream>#include <string>#include <algorithm>#include <fstream>#include <string>#define BUFFSIZE 1024using namespace std;const int PORT = 80;const char IP[]="220.181.111.148";const char RESOURCE[]="/img/baidu_sylogo1.gif";class initsock{ public: initsock() { WSADATA wsadata; if(WSAStartup(MAKEWORD(2,2),&wsadata)) { } else if(LOBYTE(wsadata.wVersion)!=2 || HIBYTE(wsadata.wVersion)!=2) { } } ~initsock() { WSACleanup(); }};int main(){ initsock s; struct sockaddr_in server_addr; /*init socket*/ int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { return -1; } // HOSTENT* web_host = gethostbyname("http://172.16.12.11"); // printf("IP: %s\n", inet_ntoa(*((struct in_addr *)web_host->h_addr_list[0]))); memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr(IP);//*((struct in_addr *)web_host->h_addr_list[0]); int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (ret<0) { printf("error\n"); } char request[BUFFSIZE]; memset(request, 0, sizeof(request)); sprintf(request, "GET %s HTTP/1.1\r\n" "Accept: */*\r\n" "Accept-Language: zh-cn\r\n" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" "\r\n",RESOURCE,IP,PORT); ret = send(sockfd, request, sizeof(request), 0); int end, recvsize, count; char recvbuf[BUFFSIZE]; fd_set read_fds; struct timeval timeout; /*建议时间要长点, select失败可能的原因是收到网站的响应消息超时*/ timeout.tv_sec = 30; timeout.tv_usec = 0; FD_ZERO(&read_fds); FD_SET(sockfd, &read_fds); string str; while (1) { ret = select(sockfd+1, &read_fds, NULL, NULL, &timeout); if (-1 == ret) { /*出错,直接返回错误*/ fprintf(stderr, "select: %s\n", strerror(errno)); return -1; } else if (0 == ret) { /*超时, 继续轮询*/ fprintf(stderr,"surpass\n"); break; } /*接受到数据*/ if (FD_ISSET(sockfd, &read_fds)) { //问题出在这里//一个情况时单个字节读取,另一个是多个字节读取,为什么多个字节读取得到的图片是错误的呢 //^#1// while (recv(sockfd, recvbuf,BUFFSIZE,0)) {//// str+=recvbuf;// }// break; ////^#1 //^#2 while (recv(sockfd, recvbuf,1,0)==1) { str+=recvbuf[0]; } break; ////$#2 } } FD_CLR(sockfd, &read_fds); string::size_type pos = str.find("\r\n\r\n"); if(pos!=string::npos) { pos+=string("\r\n\r\n").length(); // cout<<str.substr(pos); fstream out("img.gif",ios::binary|ios::out); out<<str.substr(pos); out.close(); } closesocket(sockfd); return 0;}
int n = 0; while (n = recv(sockfd, recvbuf,BUFFSIZE,0)) { //str+=recvbuf; str.append(recvbuf, n); }
[解决办法]
图片数据是二进制的,非文本, 不要用string接收,改用std::vector<unsigned char>吧.另外,recv需要判读是否还有更多的数据.