【问题标题】:read socket raise errno 9 randomly随机读取套接字引发 errno 9
【发布时间】:2021-12-31 10:07:54
【问题描述】:

我有一个通过 tcp 套接字进行通信的客户端/服务器设置。 功能明智的工作非常好,除了我在读取服务器端的套接字时随机但经常出现 errno 9 。 根据我可以找到的文档和讨论,当对本地关闭的套接字执行读取操作时,会引发 errno。 我很确定我没有在服务器端的读取循环中关闭套接字。发送消息后,套接字仅由客户端关闭。 这是服务器端的读取循环

void *client_listener_thread(void *args)
    {
    struct th_params *param = (void  *) args;
    int sockfd, n, client_pos;
    message_t messageR;
    char logbuf[256], buf[256];
    sockfd = param->socket;
    while(1)
        {
        n = read(sockfd, &messageR, sizeof(message_t));
        if (n < 0)
            {
            sprintf(logbuf, "cmd_thread: ERROR reading from socket errno=%d sock=%d thread=%x", errno, sockfd, (uint32_t)(param->client_listener));
            logwts(logbuf);
            break;
            }
        else if(n == 0)
            {
            sprintf(logbuf, "cmd_thread: socket closed by remote peer 2 %x", (uint32_t)(param->client_listener));
            logwts(logbuf);
            break;
            }
        else
            {
            inet_ntop(AF_INET, &messageR.header.sender_ip, buf, 255);
            sprintf(logbuf, "cmd_thread:URC Message: ID = %d sender = %s\n", messageR.header.messageID, buf);
            logwts(logbuf);

// process message
            switch(messageR.header.messageID)
                {
                case IDENT_ACK:
                    ...
                    sprintf(logbuf, "New client registered on socket %d  %d / %s:%d", sockfd, client_pos, buf, messageR.header.sender_port);
                    logwts(logbuf);
                    break;
                ...
                
                default:
                    sprintf(logbuf, "cmd_thread:unprocessed message %d", messageR.header.messageID);
                    logwts(logbuf);
                    break;
                }
            }
        }
    if(sockfd)
        close(sockfd);
    pthread_exit(NULL);
    } 

在客户端,它只是打开套接字,发送消息,关闭套接字。 运行时,在服务器端,我在第一次读取时收到“新客户端注册...”消息,在第二次读取时,我收到预期的“远程对等方关闭套接字...”消息或意外“从套接字读取错误.." 带有 errno = 9
正如我所说的功能没有问题,没有消息丢失,消息被接收和处理。我可以忽略这个错误,但我想先理解它。

【问题讨论】:

  • errno 9 是EBADF,意思是“错误的文件描述符”。我建议使用 perror()(或 strerror())将 errno 代码替换为更用户友好的消息。我认为read() 被错误的sockfd 调用
  • 感谢@Sinic 的评论!我正在研究相同的潜在问题,但日志显示相同的套接字编号。 [12/31/21 - 10:45:42.552] tcp_server:New cmd thread 0 **5** 12fa5700 [12/31/21 - 10:45:42.553] cmd_thread:URC Message: ID = 2 sender = 192.168.0.152 [12/31/21 - 10:45:42.553] New client registered on socket **5** 0 / 192.168.0.152:8001 [12/31/21 - 10:45:42.553] cmd_thread: ERROR reading from socket errno=9 sock=**5** thread=12fa5700
  • close() 调用之后分别返回什么值errno 是什么?我假设 close() 返回 -1 并且 errno 仍然是 9。这意味着描述符(在本例中为 5)正在其他地方关闭
  • 是的,真正的 close() 返回 -1 并且 errno 仍然是 9,但我从 2 周开始就在尝试找出代码中套接字关闭的其他位置,但什么也没找到 :( . 有没有办法为套接字操作注册一个catch?
  • 我会在每次close() 调用代码中打印即将关闭的描述符之前使用 printf 输出。如果这不起作用并且您使用的是 linux 机器,则可以使用 strace 检查应用程序进行的所有系统调用。

标签: c sockets tcp errno


【解决方案1】:

感谢 strace 可以找到罪魁祸首。 线程之间的竞争条件。一个线程正在关闭套接字,而另一个线程仍在使用它。互斥体完成了这项工作。 完全正确@Sinic 的评论 “......描述符(在本例中为 5)正在其他地方关闭......”

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 2020-10-07
  • 2013-04-04
  • 2012-02-09
  • 1970-01-01
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多