【问题标题】:How to know send() or sendmsg() successfully deliver message?如何知道 send() 或 sendmsg() 成功传递消息?
【发布时间】:2014-02-26 09:45:57
【问题描述】:

我设置了一个简单的客户端和服务器程序,使用 TCP 套接字进行通信。服务器等待客户端连接并回复是否收到客户端的消息。下面是代码在服务端和客户端的实现方式:

服务器端代码:

 listen(sockfd,5);

 clilen = sizeof(cli_addr);
 newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

 if (newsockfd < 0)
      error("ERROR on accept");
 bzero(buffer,256);

 n = read(newsockfd,buffer,255);

 if (n < 0)
     error("ERROR reading from socket");

 printf("Here is the message: %s\n",buffer);

 n = write(newsockfd,"I got your message",18);

 if (n < 0)
     error("ERROR writing to socket");

客户端代码:

if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
    error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
     error("ERROR writing to socket");
else
    printf("sucess. n = %d", n);

bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
     error("ERROR reading from socket");

现在,假设我启动了服务器,然后启动了客户端,客户端成功连接到服务器。然后我关闭服务器并尝试从客户端发送消息,write() 操作没有返回错误。我在这里期望的是一个错误,因为服务器实际上没有收到任何数据包(它已关闭)。

所以我的问题是:有没有办法知道write()(或send()sendto()sendmsg())是否成功地将消息传递到服务器?

【问题讨论】:

  • 很多人问,“如果 TCP 堆栈知道该数据包已被远程主机确认(ACK'd),为什么我的应用程序代码不能确定这一点?”原因是 TCP 只知道数据包是否被远程主机的 TCP 层确认。它不知道被确认的数据是否实际上被托管在远程端的套接字的应用程序所使用。因此,高于 TCP 的更高级别的协议(即您的代码和协议)需要提供此信号。

标签: c sockets send sendto


【解决方案1】:

没有。写或发送只是说话,他们不等待反馈(例如 TCP 的 ACK)。但是,如果您得到某种反馈,您只能确定消息已成功传递。尝试另一次发送甚至没有帮助,因为它可能会在前一条消息尚未到达客户端时执行。接收并希望出错也无济于事,因为您收到的数据可能在您发送消息之前就已由对等方发送。唯一确定的方法是在您的应用程序协议中放置某种显式握手,然后等待对您的消息的匹配响应。

【讨论】:

  • 我搜索了这个问题,好像是当服务器停止时,向客户端发送了一个SIGPIPE信号,但我仍然不知道客户端是如何捕获和处理这个信号的。
  • 种类:如果 TCP 连接关闭并且您再次尝试 send() 或 write(),您将获得 SIGIPE,或者如果您忽略系统调用返回 EPIPE 的信号。但不是,服务器将信号发送给客户端,它只是关闭连接。
【解决方案2】:

这种方式是行不通的。只要消息适合发送缓冲区,write() 就会返回成功。知道该消息已被服务器接收和处理的唯一方法是接收解析“我收到你的消息”。

write() 返回 -1 表示连接已关闭或无效,但不要指望它检测所有可能的错误。

【讨论】:

  • 第一段是正确的,但第二段有太多错误信息。如果您传递零长度,write() 仅返回零。如果您在关闭的套接字上调用它,它会返回 -1 并将 errno 设置为 EBADF。如果您在已被对等方关闭的连接上调用它,它会返回 -1 并将 errno 设置为 ECONNRESET。 -1 本身并不表示“无效连接”。
  • 感谢您的修改!
  • 这个想法实际上是解决答案。
猜你喜欢
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 2019-08-17
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多