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

如何使用strtok解析TCP服务器字符串?Socket通信无输出问题排查

Socket通信中移除"\r"分隔符解析字符串无输出问题排查与解决

问题描述

编写了一段监听服务器的程序,使用"\r"作为分隔符。但运行该程序后没有任何输出,请问如何在Socket通信中移除分隔符来解析字符串?

客户端代码

#include <arpa/inet.h> // inet_addr()
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> // bzero()
#include <sys/socket.h>
#include <unistd.h> // read(), write(), close()
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
    
    char buff[MAX];
    int n;
    char str[MAX];
    for (;;) {
        bzero(buff, sizeof(buff));
        printf("Enter the string : ");
        n = 0;
        while ((buff[n++] = getchar()) != '\n') 
            ;
        write(sockfd, buff, sizeof(buff));            
        bzero(buff, sizeof(buff));

        read(sockfd, buff, sizeof(buff));
        strcpy(str,buff);

        char delim[]="\r";
        char *str = strtok(str,delim);
        while(str != NULL)
        {
            printf("from my prog = %s \n",str);
            str = strtok(NULL,delim);
        }
        if ((strncmp(buff, "exit", 4)) == 0) {
            printf("Client Exit...\n");
            break;                                 
        }
    }
}

通信数据截图

Socket通信返回数据截图


问题排查与解决

你的代码存在几个关键问题,直接导致程序无输出:

1. 变量重定义覆盖

代码中先定义了char str[MAX];,后续又用char *str = strtok(str,delim);重新定义同名指针变量,这会覆盖之前的数组变量,导致strtok操作的内存地址异常,无法正确解析字符串。

修复:把指针变量名改成不同的,比如token:

char *token = strtok(str, delim);
while (token != NULL) {
    printf("from my prog = %s \n", token);
    token = strtok(NULL, delim);
}

2. 未处理read()返回值

read()函数可能返回0(服务器关闭连接)、-1(读取错误),或者实际读取的字节数。直接使用buff会导致读取空数据或错误数据,进而解析失败无输出。

修复:添加返回值判断,并手动给buff添加字符串终止符(\0),避免乱码:

ssize_t bytes_read = read(sockfd, buff, sizeof(buff)-1);
if (bytes_read <= 0) {
    if (bytes_read == 0) {
        printf("Server closed connection\n");
    } else {
        perror("read failed");
    }
    break;
}
buff[bytes_read] = '\0'; // 确保字符串以\0结尾

3. 发送冗余数据

当前代码用write(sockfd, buff, sizeof(buff))发送整个80字节的缓冲区,而你输入的字符串长度远小于80,剩余字节都是空字符,这会导致服务器收到冗余数据,返回的内容可能不符合预期。

修复:只发送实际输入的字节数:

// 读取输入时限制长度,避免溢出
n = 0;
while ((buff[n++] = getchar()) != '\n' && n < MAX-1);
// 发送实际输入的字节数(包括换行符\n)
write(sockfd, buff, n);

4. 分隔符适配问题

从截图看,服务器返回的数据结尾是\r\n,只用\r做分隔符的话,解析后的字符串会带有\n,如果需要去除,可以在解析后处理:

while (token != NULL) {
    size_t len = strlen(token);
    // 去掉末尾的换行符\n
    if (len > 0 && token[len-1] == '\n') {
        token[len-1] = '\0';
    }
    printf("from my prog = %s \n", token);
    token = strtok(NULL, delim);
}

修正后的完整func函数

void func(int sockfd)
{
    char buff[MAX];
    char str[MAX];
    for (;;) {
        bzero(buff, sizeof(buff));
        printf("Enter the string : ");
        int n = 0;
        // 读取输入,避免缓冲区溢出
        while ((buff[n++] = getchar()) != '\n' && n < MAX-1);
        
        // 发送实际输入的字节数
        write(sockfd, buff, n);

        bzero(buff, sizeof(buff));
        // 读取服务器返回数据并处理返回值
        ssize_t bytes_read = read(sockfd, buff, sizeof(buff)-1);
        if (bytes_read <= 0) {
            if (bytes_read == 0) {
                printf("Server closed connection\n");
            } else {
                perror("read failed");
            }
            break;
        }
        buff[bytes_read] = '\0';
        strcpy(str, buff);

        // 用\r作为分隔符解析字符串
        char delim[] = "\r";
        char *token = strtok(str, delim);
        while (token != NULL) {
            // 移除末尾的\n(如果存在)
            size_t len = strlen(token);
            if (len > 0 && token[len-1] == '\n') {
                token[len-1] = '\0';
            }
            printf("from my prog = %s \n", token);
            token = strtok(NULL, delim);
        }

        if (strncmp(buff, "exit", 4) == 0) {
            printf("Client Exit...\n");
            break;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:25:17