2010-02-01 21 views
2

下面是我在套接字编程方面遇到的代码片段。在之后选择调用,如果我没有在第9行上放置睡眠,在Windows XP上,第11行接收到1字节(而不是4字节从服务器发送为整数),当我检查xmlSize时,它被设置为0.因为iResult为1,执行继续,并在第15行第二次接收时调用xmlSize = 0,并且iResult设置为0,之后因为iResult = 0连接已关闭。C++套接字选择和接收问题

但是在Windows 7上这并没有发生,程序愉快地读取4个字节并继续正常执行。然而,在XP上,我放了一个睡眠(我只是做了这个),它的工作,但为什么?

这段代码有什么缺陷?

1 while(is_running()) 
2 { 
3  FD_ZERO(&readfds); 
4  FD_SET(server_socket, &readfds); 
5  iResult = select(server_socket+1, &readfds, NULL, NULL, &tv); 
6  if (!(iResult != SOCKET_ERROR && FD_ISSET(server_socket, &readfds))) { 
7   continue; 
8  } 
9  Sleep(500); // This Sleep is not required on Windows 7, but is required on 10 XP but WHY? 
11  iResult = recv(server_socket, (char *)&xmlSize, sizeof(xmlSize), 0); 
12  xmlSize = htonl(xmlSize); 
13  if (iResult > 0){ 
13   printf("Bytes received: %d, XML Size:%d", iResult, xmlSize); 
14   
15   iResult = recv(server_socket, xml, xmlSize, 0); 
16   if (iResult > 0){ 
17    xml[xmlSize] = '\0'; 
18    printf("Bytes received: %d", iResult);    
19    operation_connection(xml); 
20   } 
21   else if (iResult == 0){ 
22    printf(LL_INTERR, CLOG("Connection closed")); 
23    break; 
24   } 
25   else{ 
26    printf("recv failed with error: %d", WSAGetLastError()); 
27    break; 
28   } 
29  } 
30  else if (iResult == 0){ 
31   printf(LL_INTERR, CLOG("Connection closed")); 
32   break; 
33  } 
34  else{ 
35   printf("recv failed with error: %d", WSAGetLastError()); 
36   break; 
37  } 
38 } 
+1

你知道,有没有保证,通过对recv的单个呼叫(接收)的字节数相匹配的数量通过一次调用send()发送的字节? – 2010-02-01 11:44:17

+0

好吧,我现在看到了这个问题,但我不希望这样的行为,因为recv函数需要将字节数作为参数。那么你有什么建议? – whoi

+0

该数字是最大字节数,因此请继续调用recv()并调整该数字,直到读取四个字节。 – 2010-02-01 12:10:32

回答

7

如果这是一个TCP套接字,你应该不在意。插座提供,它不以任何方式或方式与原始write() s的大小对应。

它可以提供一百万字节或一个1MB字节或两者之间的任何组合。

如果您依赖于TCP连接的传递数据“块”的大小,那么您就错了。

如果您需要某种类型的消息分隔符,然后在协议中明确设计一个消息分隔符,则回车+换行方式将被例如HTTP。如果协议是ASCII,所以你不能使用这些特定字节分开的消息,有两个两个典型方法:

  • 使用一些其他的字节序列,也许是ASCII 0X1E,“记录分隔符”。
  • Escape CR + LF当它们包含在消息中时,使“普通”的作为分隔符起作用。如果你的协议“想”成为文本,这将是更好的解决方案。

另一种方法是显式编码每个消息在流本身中的长度,最好是作为前缀,以便知道需要多少数据。

+0

是的,我确实依赖于块,但像CR或LF这样的分隔符不适合我,因为我的消息包含CR LF。那么你能否提出另一种方法? – whoi

+0

如果不能使用分隔符,则使用包含魔术和数据大小的标头是一种非常常用的技术。标题可以包含不同的字段,如消息类型,消息ID,... – stefaanv

+0

@stefaanv:是的,我编辑过。谢谢! – unwind