多次调用 send() 合并为一次调用 recv()

Posted

技术标签:

【中文标题】多次调用 send() 合并为一次调用 recv()【英文标题】:Multiple calls to send() are merged into one call to recv() 【发布时间】:2014-08-23 13:26:50 【问题描述】:

我有一个客户端-服务器应用程序。

客户端使用两个不同的send() 调用发送一个字符串,后跟一个整数。这两个数据应该存储在服务器上的两个不同变量中。

问题是发送的两个变量都是在recv() 调用时收到的。因此,两个不同的send()s发送的两个字符串被链接并存储在第一个recv()的缓冲区中。

server.c:

printf("Incoming connection from client %s:%i accepted\n",inet_ntoa(clientSocketAddress.sin_addr),ntohs(clientSocketAddress.sin_port));


memset(buffer,0,sizeof(buffer));
int sizeofMessage;
if ((recv(clientSocket,buffer,MAXBUFFERSIZE,0)==sizeofMessage)<0)

  printf("recv failed.");
  closesocket(serverSocket);
  clearWinsock();
  return EXIT_FAILURE;


char* Name=buffer;
printf("Name: %s\n",Name);

if ((recv(clientSocket,buffer,MAXBUFFERSIZE,0))<0)

  printf("bind failed.");

  closesocket(serverSocket);
  clearWinsock();
  return EXIT_FAILURE;


int integer=ntohs(atoi(buffer));
printf("integer: %i\n",intero);

client.c:

if (send(clientSocket,Name,strlen(Name),0)!=strlen(Name))

  printf("send failed");

  closesocket(clientSocket);
  clearWinsock();
  return EXIT_FAILURE;


printf("client send: %s",Name);

int age=35;
itoa(htons(age),buffer,10);
sizeofBuffer=strlen(buffer);
if (send(clientSocket,buffer,sizeofBuffer,0)!=sizeofBuffer)

  printf("bind failed.");

  closesocket(clientSocket);
  clearWinsock();
  return EXIT_FAILURE;

我该如何解决?我究竟做错了什么?

【问题讨论】:

【参考方案1】:

这就是 TCP 的工作原理。将其视为字节流。 将一些基本协议放在上面 - 用一些已知的字节值分隔您的应用程序消息,或者在您的消息前面加上长度字段。

或者切换到 UDP,如果您可以容忍/从偶尔的数据包丢失中恢复,它会为您提供您正在寻找的数据报语义。

【讨论】:

“用一些已知的字节值分隔你的应用程序消息”只是为了澄清,这称为协议,有些人使用类似 STXyourmessageETXXOR 的东西,其中 HEX 中的 STX(开始)为 2,ETX(结束)在HEX 为 3,XOR 是 STXyourmessageETX 的按位运算 ^,result = STX ^ y -> result ^= u ... 其中 XOR 表示要验证的数字【参考方案2】:

TCP 是一种流协议。它根本不知道任何类型的“消息”边界。它不会添加此类信息依赖于对send() 的单个调用。

由于这些事实,发送方的任意数量的send()s 都可能导致接收方的任意数量的recv()s(最多发送的字节数)。

为了避免这种行为,定义并实现一个应用程序级协议来区分已发送的不同“消息”。

不能依赖recv()/send() 接收/发送与这两个函数被告知接收/发送一样多的字节。检查它们的返回值以了解这些函数实际接收/发送了多少字节并围绕它们循环直到所有打算接收/发送的数据都已接收/发送是必不可少的。

例如如何进行这种“循环”

写作你可能想看看这个答案:https://***.com/a/24260280/694576 和 阅读此答案:https://***.com/a/20149925/694576

【讨论】:

【参考方案3】:

如果时间在您的应用程序中并不重要,您可以在两条消息之间添加一个较短的时间间隔,例如 sleep(5)。

【讨论】:

以上是关于多次调用 send() 合并为一次调用 recv()的主要内容,如果未能解决你的问题,请参考以下文章

recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?

是否需要在对应的 MPI_Recv 之前调用 MPI_Send

TCP协议面试热点(面向字节流,粘包问题,TCP异常情况)

为啥我不能激发 TCP 将 send() 拆分为多个 recv()

IDEA 中Git 多次 Commit 合并为一次提交

IDEA 中Git 多次 Commit 合并为一次提交