You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用select()时陷入无限循环,输入Socket命令无响应

问题分析与修复

你的程序输入无响应的核心问题是读取输入时fgets参数错误,同时还有几个会导致select行为异常的bug,逐一说明:

1. fgets读取长度错误

你用strlen(buffer)作为fgets的第二个参数,但刚执行memset(buffer, 0, 300)后,buffer全是0,strlen(buffer)返回0,导致fgets读取0个字符,根本没获取到输入内容。

修复:把fgets的长度参数改成sizeof(buffer),确保能读取到最大缓冲区长度的内容:

fgets(buffer, sizeof(buffer), stdin);

2. maxfd初始化与更新逻辑错误

初始时host.TCPincoming的值是-1,你把maxfd设为这个值,后续select(maxfd + 1, ...)就变成select(0, ...),这会导致select不监听任何大于0的文件描述符(比如UDPsocket、TCPsocket等)。同时,你重复对无效fd(值为-1)执行FD_SET,这是未定义行为,会破坏fd_set结构。

修复:

  • 初始化maxfd为0(stdin的文件描述符是0)
  • 只在fd有效(不等于-1)时,才添加到fd_set并更新maxfd:
FD_ZERO(&(host.rfds));
FD_SET(0, &(host.rfds)); // 监听stdin
maxfd = 0;

// 处理UDPsocket
if (host.UDPsocket != -1) {
    FD_SET(host.UDPsocket, &(host.rfds));
    if (host.UDPsocket > maxfd) maxfd = host.UDPsocket;
}

// 处理TCPcord
if (host.TCPcord != -1) {
    FD_SET(host.TCPcord, &(host.rfds));
    if (host.TCPcord > maxfd) maxfd = host.TCPcord;
}

// 处理TCPincoming
if (host.TCPincoming != -1) {
    FD_SET(host.TCPincoming, &(host.rfds));
    if (host.TCPincoming > maxfd) maxfd = host.TCPincoming;
}

// 处理TCPsocket_next
if (host.TCPsocket_next != -1) {
    FD_SET(host.TCPsocket_next, &(host.rfds));
    if (host.TCPsocket_next > maxfd) maxfd = host.TCPsocket_next;
}

3. select的timeout被修改问题

select调用后会修改传入的timeval结构体,把它设置为剩余的超时时间。如果不重新初始化,后续循环中timeout可能变成0,导致select立即返回,造成CPU空转。

修复:把timeout的初始化放到while(1)循环内部,每次循环都重置超时时间:

while(1) {
    struct timeval timeout;
    timeout.tv_sec = 60;
    timeout.tv_usec = 0;
    
    // 后续的FD_SET、select逻辑...
}

4. 冗余的FD_SET操作

你在代码开头已经对host.TCPcord、host.TCPincoming执行了FD_SET,后面又在if判断中重复执行,这完全冗余,且当fd为-1时会触发未定义行为,必须删除开头的无效FD_SET调用。

修复后的核心代码片段

while(1) //main loop
{
    struct timeval timeout; // 每次循环重新初始化超时
    timeout.tv_sec = 60;
    timeout.tv_usec = 0;

    FD_ZERO(&(host.rfds));
    FD_SET(0, &(host.rfds)); // 监听stdin
    int maxfd = 0;

    // 加入UDPsocket
    if (host.UDPsocket != -1) {
        FD_SET(host.UDPsocket, &(host.rfds));
        if (host.UDPsocket > maxfd) maxfd = host.UDPsocket;
    }

    // 加入TCPcord
    if (host.TCPcord != -1) {
        FD_SET(host.TCPcord, &(host.rfds));
        if (host.TCPcord > maxfd) maxfd = host.TCPcord;
    }

    // 加入TCPincoming
    if (host.TCPincoming != -1) {
        FD_SET(host.TCPincoming, &(host.rfds));
        if (host.TCPincoming > maxfd) maxfd = host.TCPincoming;
    }

    // 加入TCPsocket_next
    if (host.TCPsocket_next != -1) {
        FD_SET(host.TCPsocket_next, &(host.rfds));
        if (host.TCPsocket_next > maxfd) maxfd = host.TCPsocket_next;
    }
        
    printf("starts loop\n");
    counter = select (maxfd + 1, &(host.rfds), NULL, NULL, &timeout);

    if (counter > 0)
    {
        if(FD_ISSET(0, &(host.rfds)))
        {
            printf("starts reading buffer\n");
            char buffer[300];
            memset(buffer, 0, 300);
            fgets(buffer, sizeof(buffer), stdin); // 修复读取长度
            
            int n = 0;
            char* token[5];
            token[n]=strtok(buffer, " \n");
            while(token[n]!=NULL && n<5)
            {
                n++;
                token[n] = strtok(NULL, " \n");
            }

            for (int i = 0; i<n; i++)
            {
                token[i][strcspn(token[i], "\n")] = '\0';
                printf("\ninput token: %s\n", token[i]);
            }

            if ((strcmp(token[0], "join") == 0) || (strcmp(token[0], "j") == 0))
            {
                if (host.connected) 
                {
                    printf("you are already registered\n");
                    exit(0);
                }
                printf("input command: join\n");
                join(host_ptr, token[1], token[2]);
            }
            else if ((strcmp(token[0], "exit") == 0) || strcmp(token[0], "x") == 0)
            {
                printf("Exit command. exiting...");
                exit(EXIT_SUCCESS);
            }
        }

        // 其他FD_ISSET处理逻辑...
    }
}

内容的提问来源于stack exchange,提问作者A Burial At Ornans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:30:00