【发布时间】: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检查应用程序进行的所有系统调用。