二战风云 2024-09-16 09:03 采纳率: 0%
浏览 44

关于#c++#的问题:C++ 非阻塞socket send() 报 Resource temporarily unavailable

C++ 非阻塞socket send() 报 Resource temporarily unavailable,errno 11 EAGAIN

搜索了解大概是 客户端不接收数据导致的
tcpdump信息如下


00:53:20.913298 IP 192.168.0.101.54040 > 192.168.0.104.http: Flags [S], seq 3626470018, win 65535, options [mss 1460,sackOK,TS val 2626609983 ecr 0,nop,wscale 9], length 0
00:53:20.913509 IP 192.168.0.104.http > 192.168.0.101.54040: Flags [S.], seq 2879253096, ack 3626470019, win 65160, options [mss 1460,sackOK,TS val 3242350133 ecr 2626609983,nop,wscale 6], length 0
00:53:21.026786 IP 192.168.0.101.54040 > 192.168.0.104.http: Flags [.], ack 1, win 128, options [nop,nop,TS val 2626610299 ecr 3242350133], length 0
00:53:21.031546 IP 192.168.0.101.54040 > 192.168.0.104.http: Flags [P.], seq 1:21, ack 1, win 128, options [nop,nop,TS val 2626610303 ecr 3242350133], length 20: HTTP
00:53:21.031662 IP 192.168.0.104.http > 192.168.0.101.54040: Flags [.], ack 21, win 1018, options [nop,nop,TS val 3242350251 ecr 2626610303], length 0

问一下客户端socket win为什么65535直接变成128,是不是这个问题导致的(大概不是,还有别的异常)

有的时候报了这个错,新创建的socket connect() 也一直报Resource temporarily unavailable,errno 11 EAGAIN

  • 写回答

2条回答 默认 最新

  • 越重天 新星创作者: Java技术领域 2024-09-16 11:25
    关注

    在C++中使用非阻塞socket时,send() 函数返回 Resource temporarily unavailable 错误(errno 11 EAGAIN)通常是由于发送缓冲区已满,无法立即发送数据。这种情况在非阻塞模式下是正常的,因为非阻塞socket不会等待缓冲区可用,而是立即返回错误。

    问题分析

    1. 客户端socket win从65535变成128

      • win 字段表示接收窗口的大小,即接收端可以接收的数据量。当客户端的接收缓冲区变满时,接收窗口会变小,以通知发送端减少发送的数据量。
      • 从65535变成128,说明客户端的接收缓冲区已经接近满载,导致接收窗口变小。这是一个正常的现象,表明客户端的接收缓冲区可能没有及时处理接收到的数据。
    2. send() 返回 EAGAIN

      • 这通常是因为发送缓冲区已满,无法立即发送数据。非阻塞socket在这种情况下会立即返回EAGAIN错误。
    3. 新创建的socket connect() 也报 EAGAIN

      • 这可能是由于系统资源不足或网络堆栈繁忙导致的。EAGAIN错误表示资源暂时不可用,可能是因为系统资源(如文件描述符、内存等)不足。

    解决方案

    1. 处理EAGAIN错误

      • 在非阻塞模式下,当send()返回EAGAIN错误时,应该使用select()poll()epoll()等机制来等待发送缓冲区变为可用状态,然后再尝试发送数据。
      #include <sys/socket.h>
      #include <sys/select.h>
      #include <unistd.h>
      
      int send_data(int sockfd, const char* data, size_t len) {
          while (len > 0) {
              ssize_t sent = send(sockfd, data, len, MSG_NOSIGNAL);
              if (sent == -1) {
                  if (errno == EAGAIN || errno == EWOULDBLOCK) {
                      // 等待发送缓冲区变为可用
                      fd_set writefds;
                      FD_ZERO(&writefds);
                      FD_SET(sockfd, &writefds);
                      select(sockfd + 1, nullptr, &writefds, nullptr, nullptr);
                      continue;
                  } else {
                      // 其他错误处理
                      return -1;
                  }
              }
              data += sent;
              len -= sent;
          }
          return 0;
      }
      
    2. 检查系统资源

      • 如果新创建的socket在connect()时也返回EAGAIN,可能是系统资源不足。可以通过以下方式检查系统资源:
        • 检查文件描述符限制:ulimit -n
        • 检查内存使用情况:free -m
        • 检查网络堆栈状态:netstat -s
    3. 优化客户端接收缓冲区处理

      • 确保客户端及时处理接收到的数据,避免接收缓冲区变满。可以通过增加接收缓冲区的大小或优化接收数据的处理逻辑来解决。

    总结

    Resource temporarily unavailable 错误在非阻塞socket中是常见的,通常是由于发送缓冲区已满或系统资源不足导致的。通过使用select()poll()epoll()等机制来等待缓冲区变为可用状态,可以有效处理这种错误。同时,确保客户端及时处理接收到的数据,避免接收缓冲区变满,也是解决问题的关键。

    评论

报告相同问题?

问题事件

  • 修改了问题 9月16日
  • 修改了问题 9月16日
  • 修改了问题 9月16日
  • 修改了问题 9月16日
  • 展开全部