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

IO多路复用聊天室首连客户端IP显示为0.0.0.0问题求助

客户端IP显示为0.0.0.0的问题排查与解决

问题描述

用IO多路复用实现简易聊天室时,发现首个连接服务器的客户端IP始终显示为0.0.0.0,但客户端配置的连接地址明明是127.0.0.1。

复现步骤

  • 执行命令gcc server.c -o server && echo "compile finished" && ./server启动服务器;
  • 编译客户端:gcc client.c -o client;
  • 启动客户端后按Ctrl-C中断,此时可观察到首个客户端IP显示为0.0.0.0。

代码示例

服务端代码

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
#include <setjmp.h>


#define SERVER_PORT 9098
#define MAX_OR_ADD_LENGTH 100
#define MAX_NAME_SIZE 40

int main(void){
    /*
     * create an array about three socket fd, the first is server
     * */
    int array_fds[3], array_index = 1;
    int max_fd_p;
    int server_fd = socket(AF_INET, SOCK_STREAM, 0), client_fd;
    // create
    if(server_fd == -1){
        perror("create socket descriptor error:");
        exit(-1);
    }
    char message[1024];
    socklen_t len;
    struct sockaddr_in server_addr, client_addr;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_family = AF_INET;
    if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) != 1){
        perror("alloc address error");
        exit(-1);
    }
    if(bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0){
        perror("bind error:");
        exit(-1);
    }
    listen(server_fd, 1000);
    //
    ssize_t n;
    //
    array_fds[0] = server_fd;
    max_fd_p = server_fd + 1;
    fd_set fds;
    while (1){
        // IO multiplexing
        int max_resp;
        FD_ZERO(&fds);
        memset(message, 0, sizeof(message));
        //
        for(int i=0;i<3;i++){
            // if exit not add to select read list
            if(array_fds[i] != -1){
                FD_SET(array_fds[i], &fds);
            }
        }
        if((max_resp = select(max_fd_p, &fds, NULL, NULL, NULL)) == -1){
            perror("select error");
            break;
        }
        for(int i=2; i>=0 && max_resp ;i--){
            if(!FD_ISSET(array_fds[i], &fds)){
                continue;
            }
            max_resp--;
            if(array_fds[i] == server_fd){
                client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);
                inet_ntop(AF_INET, &client_addr.sin_addr, message, sizeof(message));
                printf("ip is %s\n", message);
                array_fds[array_index] = client_fd;
                // add to select read list
                if(client_fd >= max_fd_p){
                    // update maxfdp
                    max_fd_p = client_fd + 1;
                }
                array_index++;
                continue;
            }
            if((n = read(array_fds[i], message, 1024)) != -1) {
                if(n == 0){
                    // if client exit, close and remove it;
                    array_fds[i] = -1;
                    close(array_fds[i]);
                    continue;
                }
                if(write(array_fds[i], "ok, got your message", n) == -1){
                    perror("write error");
                }
            }
        }
    }
    exit(0);
}

客户端代码

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>


#define SERVER_PORT 9098

int main(void){
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(client_fd == -1){
        perror("create socket error");
        exit(-1);
    }
    struct sockaddr_in client_addr;
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(SERVER_PORT);
    if(inet_pton(AF_INET, "127.0.0.1", &client_addr.sin_addr.s_addr) == -1){
        perror("address error:");
        exit(-1);
    }
    if(connect(client_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)) == -1){
        perror("connect error");
        exit(-1);
    }
    char message[1024], input_message[1024];
    ssize_t n;
    printf("input your name:");
    fgets(input_message, 1024, stdin);
    if(write(client_fd, input_message, 1024) == -1){
        perror("write error");
    }
    while (1){
        memset(message, 0, sizeof(message));
        if((n = read(client_fd, message, 1024)) != -1){
            message[n] = 0;
            printf("[server]: %s\n", message);
        }
        memset(message, 0, sizeof(message));
        printf("input message you want to send:");
        fgets(input_message, 1024, stdin);

        if(write(client_fd, input_message, 1024) == -1){
            perror("write error");
        }

    }
}

问题截图

问题截图

原因分析与修复方案

问题原因

服务端代码中调用accept函数时,第三个参数socklen_t len未初始化。accept的第三个参数是输入输出参数:调用时需要传入缓冲区(client_addr)的大小,内核才会把完整的客户端地址信息写入缓冲区。未初始化的len是随机值,大概率小于struct sockaddr_in的实际大小,导致内核无法完整写入客户端IP地址,最终inet_ntop解析出错误的0.0.0.0。

修复方案

在调用accept前,给len赋值为client_addr的大小:

// 新增这行初始化代码
len = sizeof(client_addr);
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);

修改后,accept能正确获取客户端的完整地址信息,解析出的IP就会是客户端实际连接的127.0.0.1。

内容的提问来源于stack exchange,提问作者ssayno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:47:03