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

C语言send/recv使用出现空指针及Bad Address错误问题求解

问题根因与修复方案

1. recv返回Bad Address的直接原因

客户端代码里的tmp是未初始化的野指针:recv的第二个参数需要指向一块合法、可写、大小足够的内存空间,如果tmp没有提前申请内存(要么用malloc分配对应结构体大小的堆空间,要么直接声明栈结构体实例传地址),内核无法向非法地址写入数据,就会抛出该错误。

2. 服务端if分支的两个致命错误

  • 发送长度计算错误:send(client,usr,sizeof(usr),0)中的usr是指针类型,sizeof(usr)取的是指针本身的长度(32位系统4字节、64位系统8字节),不是你要发送的结构体的实际大小,导致只会发部分结构体数据,内容不全。正确长度应该取sizeof(*usr),即指针指向的结构体的大小。
  • 跨进程传递指针的认知误区:服务端的usr是服务端进程虚拟地址空间里的地址,仅在服务端进程内有效,发到客户端没有任何意义。你需要传递的是usr指向的结构体数据内容,客户端拿到数据后写入自己进程的结构体变量中,而不是用指针直接承接。

修复代码示例

服务端修复
usr = uslist_return(&users,i);
if(usr != NULL)
{
    // 发送usr指向的完整结构体数据,长度用结构体本身的大小
    send(client, usr, sizeof(*usr), 0);
    //Some extra code
}
else
{
    utmp.userid = -1;
    send(client,&utmp,sizeof(utmp),0);
}
客户端修复
// 方法1:直接用栈上的结构体实例,避免野指针问题
struct 你的结构体类型 tmp_obj;
// 必须判断recv返回值,不要直接使用接收的数据
ssize_t recv_len = recv(sock, &tmp_obj, sizeof(tmp_obj), 0);
if(recv_len < 0) {
    perror("recv failed");
    // 错误处理逻辑
} else if(recv_len != sizeof(tmp_obj)) {
    // 处理TCP粘包、分片场景,单次接收数据不完整,需要循环接收
} else {
    if(tmp_obj.userid > 0) {
        //Some Code
    } else {
        //Some other code
    }
}

// 方法2:如果必须用指针,提前分配内存
struct 你的结构体类型 *tmp = malloc(sizeof(struct 你的结构体类型));
if(tmp == NULL) {
    // 内存分配失败处理
}
ssize_t recv_len = recv(sock, tmp, sizeof(*tmp), 0);
// 后续判断逻辑同上,使用完后记得free(tmp)避免内存泄漏

额外注意事项

  • TCP是流协议,存在粘包、分片的可能,单次recv不一定能收到完整的一个结构体大小的数据,需要实现循环接收逻辑,直到拿到期望长度的数据再解析。
  • 跨网络传输结构体要注意字节序、结构体对齐的问题,避免不同架构、不同编译选项的两端解析数据不一致,复杂场景建议先做序列化再传输。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 06:30:04