我正在为Windows和Linux上的Berkley套接字编写包装。测试程序在这里出现问题:
char buf[BUFSIZE];
int res = 0;
while((res = NetRecv(sock, buf, BUFSIZE, 0)) > 0) // 'NetRecv' is pointing to 'recv'
{
buf[res-1] = '\0';
printf("%s", buf);
}
响应是对网页内容的HTTP-Get请求。套接字正在流式传输。
' NetRecv '已正确初始化-也就是说,函数的指针没有类型不匹配,我已经检查了它。
因此,Windows版本可完美运行,而Linux一经阅读所有页面即被卡住。即,最后一个 NetRecv 调用的前一个接受响应的最后一个块,将其输出,而下一个(最后)调用只是阻塞。关闭终端会导致“ SIGHUP ”信号。 看起来Linux版本并没有意识到,它收到了最后一块数据,然后等待更多数据。
是应该的吗?那就不明白了,由于什么原因阻止了通话。 现在,我当然可以拨打非阻塞电话并使用' select ',但是我真的必须这样做吗?
先谢谢了
编辑:最小的工作示例(所有检查都被省略,并且网络功能是标准功能,并且已经过测试):
int sock = socket(AF_INET, SOCK_STREAM, 0);
// Here getting good IP address of google.com - no problem here
char serv_ip[IPADDR_BUFSIZE];
GetHostAddrByName(AF_INET, "www.google.com", serv_ip, IPADDR_BUFSIZE);
// ip ver site out buf out buf size
// The routine above is made with 'getaddrinfo', to be precise
printf("Current IP of '%s' is '%s'.\n", SERV_URL, serv_ip);
// Copying IP string to address struct
struct sockaddr_in addr;
NetIpFromStr(AF_INET, serv_ip, &addr.sin_addr);
addr.sin_family = AF_INET;
addr.sin_port = NetHtons(80);
connect(sock, (const struct sockaddr*)&addr, sizeof(addr));
const char* msg = "GET / HTTP/1.1\r\n\r\n";
send(sock, msg, strlen(msg), 0);
char buf[BUFSIZE];
int res = 0;
while((res = recv(sock, buf, BUFSIZE-1, 0)) > 0)
{
buf[res] = '\0';
printf("%s", buf);
}
EDIT 2 :重要说明:读取所有数据后,Windows版本也会阻止该呼叫。关闭终端不会使程序崩溃,就像在Linux中那样。因此,整个问题是这样的: 如何实现读取所有数据?
答案 0 :(得分:2)
问题是您正在盲目地从套接字读取循环,直到发生错误为止。收到整个响应后,您将返回套接字并继续阅读,然后继续进行阅读,因为没有什么可阅读的内容了。此时唯一可能发生的错误是连接关闭(或断开)时,服务器可能不会执行此操作,因为您正在发送HTTP 1.1请求,其中keep-alive是1.1的默认行为(请参见{{ 3}})
正确解决方案是解析HTTP响应,并在到达响应末尾时停止从套接字读取,而不仅仅是依靠服务器来关闭套接字。阅读RFC 2616 Section 8.1 Persistent Connections,了解如何检测何时到达响应结尾。阅读的内容不要超过响应指示!一旦停止阅读,您就可以决定是关闭插槽末端,还是将其重新用于新请求。
请查看RFC 2616 Section 4.4 Message Length,了解您需要使用的解析和读取逻辑的类型。
此外,您的HTTP请求格式不正确,因为您没有发送必需的 this pseudo code,因此无论如何,您始终会收到来自任何HTTP的400 Bad Request
响应1.1兼容服务器:
const char* msg = "GET / HTTP/1.1\r\n"
"Host: www.google.com\r\n" // <-- add this!
"\r\n";
答案 1 :(得分:-1)
解决方案是在Windows和Linux中关闭套接字进行读取:
// after sending a request:
shutdown(sock, SD_SEND); // or 'SHUT_WR' in Linux
// now read loop
奇怪的是,在Winsock教程中也调用了' shutdown ',但我认为这是不必要的。