简体   繁体   English

c ++套接字选择和接收问题

[英]c++ Socket select and receive problem

Below is the code fragment I have issue with socket programing. 下面是我遇到套接字编程问题的代码片段。 Here after select call, If I do not put a sleep on line 9, on Windows XP, 1 byte is received on line 11 (instead 4 byte is sent from server as integer), when I check xmlSize, it is set to 0. Because iResult is 1, execution continues and on line 15 second receive is called with xmlSize=0, and iResult is set to 0 and afterwards because iResult=0 connection is closed. 选择调用之后,如果我没有在第9行上睡眠,在Windows XP上,第11行接收到1个字节(而不是从服务器发送4个字节作为整数),当我检查xmlSize时,它被设置为0。因为iResult是1,所以执行继续,并且在第15行第二次接收被调用xmlSize = 0,并且iResult被设置为0,之后因为iResult = 0连接被关闭。

But on Windows 7 this did not happen, program happily read 4 bytes and continued normal execution. 但是在Windows 7上没有发生这种情况,程序很乐意读取4个字节并继续正常执行。 On XP however I put a sleep(I just made this up) and it worked, but Why?? 然而在XP上,我睡了一觉(我刚刚做了这个)并且它有效,但为什么?

What is the flaw in this code? 这段代码的缺陷是什么?

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  }

If this is a TCP socket, you shouldn't care. 如果这是一个TCP套接字,你不应该在乎。 The socket delivers a stream , it's doesn't correspond in any way or fashion to the size of the original write() s to the other end. 套接字传递一个 ,它不会以任何方式或方式与原始write() s的大小相对应。

It could deliver a megabyte as one million 1-byte read() s, or as a single 1MB one, or any combination in between. 它可以提供一兆字节作为一百万个1字节read() ,或者作为单个1MB一个,或两者之间的任意组合。

If you depend on the size of the delivered data "chunks" for a TCP connection, you're doing it wrong. 如果您依赖于TCP连接的传递数据“块”的大小,那么您做错了。

If you need some kind of message separator, then explicitly design one into your protocol, the way carriage return+linefeed is used by eg HTTP. 如果你需要某种消息分隔符,那么在你的协议中明确地设计一个,例如HTTP使用回车+换行的方式。 If your protocol is ASCII so you can't use these particular bytes to separate messages, there are of two two classic approaches: 如果您的协议是ASCII,那么您不能使用这些特定字节来分隔消息,有两种经典方法:

  • Use some other byte sequence, perhaps ASCII 0x1E, the "record separator". 使用其他字节序列,也许是ASCII 0x1E,“记录分隔符”。
  • Escape the CR+LF when they're contained in the message, to make "plain" ones work as separators. 当它们包含在消息中时, 转义 CR + LF,使“普通”的CR + LF作为分隔符。 This would be the better solution if your protocol "wants" to be text. 如果您的协议“希望”成为文本,这将是更好的解决方案。

Another approach is to explicitly encode the length of each message in the stream itself, preferably as a prefix so you know how much data to expect. 另一种方法是显式地编码流本身中每条消息的长度,最好作为前缀,以便您知道预期的数据量。

See this other SO question for an answer and code example: 请参阅另一个SO问题以获得答案和代码示例:

Read from socket: Is it guaranteed to at least get x bytes? 从套接字读取:是否保证至少获得x个字节?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM