meiwua 2024-11-09 15:47 采纳率: 25%
浏览 5

select监听客户端,客户端断开后服务器不输出报错信息

今天遇到了一个巨诡异的代码,用select监听客户端,客户端断开后服务器不输出报错信息,只有将errno加到printf里面会输出

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cctype>
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/select.h>
#include <string.h>
int main()
{

    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8080);
    int ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
    int opt = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
    if (ret < 0)
    {
        printf("bind error happened");
        exit(-1);
    }
    int listen_ret = listen(listen_fd, 64);
    if (listen_ret < 0)
    {
        printf("listen error happened");
        exit(-1);
    }

    struct sockaddr_in addr_in;
    socklen_t len;

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(listen_fd, &readfds);
    fd_set tmpfds;
    FD_ZERO(&tmpfds);
    int maxfds = listen_fd;
    char buf[1024];
    while (1)
    {
        tmpfds = readfds;
        int ret = select(maxfds + 1, &tmpfds, NULL, NULL, NULL);
        if (ret < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            printf("select error happened");
            break;
        }
        if (FD_ISSET(listen_fd, &tmpfds))
        {
            struct sockaddr_in addr_in;
            socklen_t len = sizeof(addr_in);
            int fd = accept(listen_fd, (struct sockaddr *)&addr_in, &len);
            if (fd < 0)
            {
                if (errno == EINTR)
                {
                    continue;
                }
                printf("accept error happened");
                break;
            }
            FD_SET(fd, &readfds);
            if (maxfds < fd)
            {
                maxfds = fd;
            }

            len = sizeof(addr_in);
            char ip[16];
            inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, ip, sizeof(ip));
            int port = ntohs(addr_in.sin_port);
            printf("ip:%s port:%d\n", ip, port);
            printf("listen fd:%d fd:%d\n", listen_fd, fd);

            if (--ret == 0)
            {
                continue;
            }
        }
        for (int pos = listen_fd + 1; pos <= maxfds; pos++)
        {
            if (FD_ISSET(pos, &tmpfds))
            {
                memset(buf, 0x00, sizeof(buf));

                int n = read(pos, buf, sizeof(buf));
                printf("%d", n);
                if (n <= 0)
                {
                    printf("read error happened or connection closed");
                    //printf("read error happened or connection closed %d\n", errno);
                    close(pos);
                    FD_CLR(pos, &readfds);
                }
                else
                {
                    for (int i = 0; i < n; i++)
                    {
                        buf[i] = toupper(buf[i]);
                    }
                    printf("%s", buf);
                    write(pos, buf, n);
                    if (--ret == 0)
                    {
                        break;
                    }
                }
            }
        }
    }
    close(listen_fd);
    return 0;
}

来个好哥们看看

  • 写回答

1条回答 默认 最新

  • 无疆76 2024-11-09 15:48
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    这段代码确实存在一些问题,特别是在处理客户端断开连接的情况。当客户端断开连接时,read()函数会返回0,表示没有数据可读,此时你正确地关闭了socket并清除了fd_set中的相关位。但是,你没有检查errno来确认是否发生了错误或客户端正常断开连接。由于你的代码中未包含具体的错误处理逻辑,所以当发生错误时(例如,当read()由于某些原因返回负值时),你无法确定是因为发生了真正的错误还是客户端已经关闭了连接。因此,虽然你的代码没有直接输出错误信息,但实际上是在处理过程中可能发生的错误并未被适当地处理。

    针对你的问题,我建议你增加错误处理逻辑,使用perror()函数或自定义的错误处理方式来输出错误信息。在read()函数返回负值时检查errno来确定错误的类型并据此进行相应的处理。此外,你也可以考虑使用更现代的异步IO库(如libevent或Boost.Asio)来处理网络连接,这些库提供了更高级的抽象和更好的性能。以下是改进后的代码片段示例:

    // 其他代码不变...
            if (n <= 0)
            {
                // 添加错误处理逻辑
                if (errno != 0) { // 检查是否有错误发生
                    perror("read error"); // 使用perror输出错误信息
                } else { // 正常关闭连接的处理逻辑
                    printf("connection closed\n"); // 输出连接关闭信息
                }
                close(pos); // 关闭socket
                FD_CLR(pos, &readfds); // 清除fd_set中的相关位
            } else { // 有数据可读时的处理逻辑保持不变... }
    

    另外,根据你的需求,你可能还需要在客户端断开连接时执行其他操作,例如重新接受新的连接或进行其他清理工作等。根据你的具体情况进行修改和完善代码。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月9日