【问题标题】:c++ Socket select and receive problemc++ Socket 选择和接收问题
【发布时间】:2010-02-02 06:51:35
【问题描述】:

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

但在 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  }

【问题讨论】:

  • 你知道单次调用recv()接收的字节数不能保证单次调用send()发送的字节数吗?
  • 好的,我现在看到了问题,但我没想到会出现这种行为,因为 recv 函数将字节数作为参数。那么你有什么建议呢?
  • 该数字是最大字节数,因此请继续调用 recv() 并调整该数字,直到您读取了四个字节。

标签: c++ select sockets recv


【解决方案1】:

如果这是一个 TCP 套接字,您不必在意。套接字传递了一个,它与另一端的原始write()s 的大小不对应。

它可以以 100 万个 1 字节 read()s 或单个 1MB 的形式提供一兆字节,或两者之间的任何组合。

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

如果您需要某种消息分隔符,则在您的协议中明确设计一个,例如使用回车+换行符的方式。 HTTP。如果您的协议是 ASCII,因此您不能使用这些特定字节来分隔消息,则有两种经典方法:

  • 使用其他字节序列,可能是 ASCII 0x1E,即“记录分隔符”。
  • Escape CR+LF 当它们包含在消息中时,使“普通”的用作分隔符。如果您的协议“想要”是文本,这将是更好的解决方案。

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

【讨论】:

  • 是的,我确实依赖于块,但是像但是 CR 或 LF 这样的分隔符对我来说不是一个选项,因为我的消息包含 CR LF。那么你能建议另一种方法吗?
  • 如果不能使用分隔符,则使用包含魔法和数据大小的标题是一种常用的技术。标头可以包含不同的字段,例如消息类型、消息 ID、...
【解决方案2】:

有关答案和代码示例,请参阅此其他 SO 问题:

Read from socket: Is it guaranteed to at least get x bytes?

【讨论】:

    猜你喜欢
    • 2011-05-30
    • 2018-11-12
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    相关资源
    最近更新 更多