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

Linux下C语言Socket客户端/服务端登录后无响应问题排查

问题分析:输入用户名后客户端与服务端无响应的原因及修复方案

我帮你排查了代码中的几个关键问题,导致输入用户名回车后双方无响应的核心原因和修复方法如下:

1. 服务端未检查密码文件是否成功打开(最直接原因)

在readUser和readPass函数中,你调用fopen("passwd.txt", "r")后没有检查返回值。如果当前目录下不存在passwd.txt,或者服务端没有读取权限,fopen会返回NULL。后续代码中while (!feof(f1))使用NULL文件指针调用feof,这会触发未定义行为,通常表现为服务端无限循环卡住,无法给客户端返回任何响应,客户端则一直阻塞在read调用上等待回复,最终双方都无响应。

修复方法:

在打开文件后立即添加检查逻辑:

// 在readUser函数中
f1 = fopen("passwd.txt", "r");
if (f1 == NULL) {
    error("ERROR opening passwd.txt");
}

// 在readPass函数中同样添加该检查

2. 密码文件解析的格式错误

readPass函数中的sscanf格式字符串写错了:

sscanf(newbuf, "%[^:]_%[^:]", user, pass);

你使用了下划线_作为用户名和密码的分隔符,但密码文件的格式应该是用户名:密码(冒号分隔),这会导致密码无法被正确读取,后续的密码验证逻辑失效。另外,fgets会读取行尾的换行符,需要在格式字符串中排除它避免密码包含换行符。

修复方法:

修改为冒号分隔,并排除换行符:

sscanf(newbuf, "%[^:]:%[^\n]", user, pass);

3. 错误的条件判断(赋值代替比较)

客户端和服务端多处出现if (n = 0)的错误写法,这是赋值操作而非比较操作,会导致错误判断完全失效(比如write/read失败时无法触发错误处理)。虽然这不是直接导致无响应的原因,但会隐藏其他潜在问题。

修复方法:

所有此类判断都改为if (n < 0)(因为write和read返回-1表示错误,返回0表示连接关闭):

// 客户端sendUser函数中
if (n < 0) { error("ERROR writing to socket"); }

// 客户端main函数中读取响应的判断
if (n < 0) { error("ERROR reading from socket"); }

// 服务端sendResponse等函数中的判断同理修改

4. 低效且易出错的文件读取逻辑

readUser中找到用户名后,readPass重新打开文件并循环到对应行读取密码,这种方式不仅低效,还可能因为文件在两次读取之间被修改导致数据不一致。更合理的做法是在readUser中找到匹配的用户名时直接提取对应的密码,传递给后续逻辑。

优化示例:

修改readUser函数,找到匹配用户时直接获取密码并调用密码验证:

int readUser(int newsockfd, int n, char buffer[]) {
    bzero(buffer, 256);
    n = read(newsockfd,buffer,255);
    if (n < 0) { error("ERROR reading from socket"); }
    printf("Received username: %s\n", buffer);

    char valid[1];
    char newbuf[256];
    char user[8];
    char pass[8];
    FILE *f1 = fopen("passwd.txt", "r");
    if (f1 == NULL) { error("ERROR opening passwd.txt"); }

    while (fgets(newbuf, 256, f1) != NULL) {
        sscanf(newbuf, "%[^:]:%[^\n]", user, pass);
        if (strcmp(buffer, user) == 0) {
            fclose(f1); // 及时关闭文件
            n = write(newsockfd, "1", 1);
            if (n < 0) error("ERROR writing to socket");
            // 直接调用密码验证,传递已获取的密码
            return verifyPass(newsockfd, n, buffer, pass);
        }
    }
    fclose(f1);
    n = write(newsockfd, "Invalid username, please try again\n", 34);
    if (n < 0) error("ERROR writing to socket");
    return 0;
}

// 新增verifyPass函数代替原readPass
int verifyPass(int newsockfd, int n, char buffer[], char *correctPass) {
    bzero(buffer, 256);
    n = read(newsockfd,buffer,255);
    if (n < 0) { error("ERROR reading from socket"); }
    if (strcmp(buffer, correctPass) == 0) {
        n = write(newsockfd, "1", 1);
        if (n < 0) error("ERROR writing to socket");
        sendResponse(newsockfd, n);
        return 1;
    } else {
        n = write(newsockfd, "Invalid password, please try again\n", 33);
        if (n < 0) error("ERROR writing to socket");
        return 0;
    }
}

额外注意事项

  • 服务端当前只能处理一个客户端连接,处理完后就退出了,如果需要支持多客户端,需要结合fork或线程实现(你代码中注释了fork相关代码,可以完善这部分逻辑)。
  • 客户端的ncurses操作中,addch('*')应该指定窗口(比如waddch(login, '*')),否则可能无法正确显示密码输入的星号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:27:30