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

UDP套接字通信异常:客户端无法接收服务器回复的问题排查

UDP通信客户端无法接收服务器回复的问题

在UDP套接字通信场景中,客户端发送消息后,服务器能成功接收并输出该消息,随后向客户端发送回复,但客户端无法接收到该回复。以下是客户端与服务器的UDP套接字实现代码:

客户端UDP套接字代码

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

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int sock;
    char message[BUF_SIZE];
    char clntmessage[BUF_SIZE];
    char servmessage[BUF_SIZE];
    int str_len;
    socklen_t adr_sz;
    
    struct sockaddr_in serv_adr, from_adr;
    if(argc!=3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }
    
    sock=socket(PF_INET, SOCK_DGRAM, 0);   
    if(sock==-1)
        error_handling("socket() error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
    serv_adr.sin_port=htons(atoi(argv[2]));
    
    while(1)
    {
        fputs("Insert message(q or Q quit): ", stdout);
        fgets(clntmessage, sizeof(message), stdin);   
        sendto(sock, clntmessage, strlen(clntmessage), 0,
            (struct sockaddr*)&serv_adr, sizeof(serv_adr));

        if (!strcmp(clntmessage, "q\n") || !strcmp(clntmessage, "Q\n")) {
            adr_sz = sizeof(from_adr);
            str_len = recvfrom(sock, servmessage, BUF_SIZE, 0,
                (struct sockaddr*)&from_adr, &adr_sz);
            printf("Message from server: %s", servmessage);
            if (!strcmp(servmessage, "bye\n"))
                break;
            else 
                servmessage[str_len] = 0;
                printf("Message from server: %s", servmessage);
                continue;
    }
    
    adr_sz=sizeof(from_adr);
    str_len=recvfrom(sock, servmessage, BUF_SIZE, 0, 
                (struct sockaddr*)&from_adr, &adr_sz);

    servmessage[str_len]=0;
    printf("Message from server: %s", servmessage);
}   
close(sock);
return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

服务器UDP套接字代码

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

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int serv_sock;
    char send_message[BUF_SIZE];
    char recv_message[BUF_SIZE];
    int str_len;
    socklen_t clnt_adr_sz;
    
    struct sockaddr_in serv_adr, clnt_adr;
    if(argc!=2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    
    serv_sock=socket(PF_INET, SOCK_DGRAM, 0);
    if(serv_sock==-1)
        error_handling("UDP socket creation error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
    serv_adr.sin_port=htons(atoi(argv[1]));
    
    if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
        error_handling("bind() error");

    while(1) 
    {
        str_len = recvfrom(serv_sock, recv_message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
    

        if (!strcmp(recv_message, "q\n") || !strcmp(recv_message, "Q\n")) {
            sendto(serv_sock, "bye", 4, 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
            printf("Message received from Client: %s", recv_message);
            break;
        }
        recv_message[str_len] = 0;
        printf("Message received from Client: %s", recv_message);

        
        fputs("Insert message: ", stdout);
        fgets(send_message, sizeof(send_message), stdin);
        sendto(serv_sock, send_message, strlen(send_message), 0, (struct sockaddr*)&clnt_adr, sizeof(clnt_adr));
        
    }   
    close(serv_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

问题原因分析

  • 客户端缩进逻辑错误:if退出分支里的else未加花括号,导致只有servmessage[str_len] = 0;属于分支内容,后续代码逻辑混乱,出现重复接收、无效判断的情况。
  • 服务器回复字符串不匹配:服务器收到退出指令时发送"bye",但客户端判断的是"bye\n",字符串不匹配导致客户端无法正常退出,持续阻塞等待。
  • 服务器地址长度参数错误:正常回复时,sendto使用sizeof(clnt_adr)作为地址长度,而非recvfrom返回的实际地址长度clnt_adr_sz,虽IPv4下数值相同,但属于不规范写法,可能引发异常。
  • 字符串终止时机错误:服务器在判断退出条件前未终止接收到的字符串,可能导致strcmp判断失效;客户端在接收服务器回复后,部分场景未先终止字符串就打印判断,存在内存越界风险。

修复后的代码

修复后的客户端代码

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

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int sock;
    char clntmessage[BUF_SIZE];
    char servmessage[BUF_SIZE];
    int str_len;
    socklen_t adr_sz;
    
    struct sockaddr_in serv_adr, from_adr;
    if(argc!=3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }
    
    sock=socket(PF_INET, SOCK_DGRAM, 0);   
    if(sock==-1)
        error_handling("socket() error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
    serv_adr.sin_port=htons(atoi(argv[2]));
    
    while(1)
    {
        fputs("Insert message(q or Q quit): ", stdout);
        fgets(clntmessage, sizeof(clntmessage), stdin);   
        sendto(sock, clntmessage, strlen(clntmessage), 0,
            (struct sockaddr*)&serv_adr, sizeof(serv_adr));

        if (!strcmp(clntmessage, "q\n") || !strcmp(clntmessage, "Q\n")) {
            adr_sz = sizeof(from_adr);
            str_len = recvfrom(sock, servmessage, BUF_SIZE, 0,
                (struct sockaddr*)&from_adr, &adr_sz);
            servmessage[str_len] = 0;
            printf("Message from server: %s", servmessage);
            if (!strcmp(servmessage, "bye\n"))
                break;
            continue;
        }
        
        adr_sz=sizeof(from_adr);
        str_len=recvfrom(sock, servmessage, BUF_SIZE, 0, 
                    (struct sockaddr*)&from_adr, &adr_sz);

        servmessage[str_len]=0;
        printf("Message from server: %s", servmessage);
    }   
    close(sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

修复后的服务器代码

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

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int serv_sock;
    char send_message[BUF_SIZE];
    char recv_message[BUF_SIZE];
    int str_len;
    socklen_t clnt_adr_sz;
    
    struct sockaddr_in serv_adr, clnt_adr;
    if(argc!=2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    
    serv_sock=socket(PF_INET, SOCK_DGRAM, 0);
    if(serv_sock==-1)
        error_handling("UDP socket creation error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
    serv_adr.sin_port=htons(atoi(argv[1]));
    
    if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
        error_handling("bind() error");

    while(1) 
    {
        clnt_adr_sz = sizeof(clnt_adr);
        str_len = recvfrom(serv_sock, recv_message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
        
        recv_message[str_len] = 0;
        printf("Message received from Client: %s", recv_message);

        if (!strcmp(recv_message, "q\n") || !strcmp(recv_message, "Q\n")) {
            sendto(serv_sock, "bye\n", 5, 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
            break;
        }
        
        fputs("Insert message: ", stdout);
        fgets(send_message, sizeof(send_message), stdin);
        sendto(serv_sock, send_message, strlen(send_message), 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
        
    }   
    close(serv_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

关键修复点说明

  • 客户端:修正else分支缩进逻辑,去掉冗余代码;接收回复后先终止字符串再进行打印和判断。
  • 服务器:初始化recvfrom的地址长度变量;发送退出回复时使用带换行符的"bye\n";统一用clnt_adr_sz作为sendto的地址长度参数;接收消息后先终止字符串再判断退出条件。

内容的提问来源于stack exchange,提问作者허준영

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:50:57