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

C++ TCP套接字发送结构体求助:服务端接收与读取疑问

解决TCP套接字发送结构体的问题

嘿,作为socket编程新手,遇到结构体发送的问题很正常——咱们先拆解你代码里的几个关键问题,然后给出能正常工作的方案~

你的代码里的核心问题

我先帮你梳理下当前代码里导致接收失败或无法正确读取的原因:

  • 服务端用错了套接字:你在服务端用sock(监听套接字)调用recv,但实际上accept返回的cli才是和客户端通信的已连接套接字,监听套接字只能用来接受新连接,不能收发数据。
  • std::string不能直接序列化发送:std::string是C++对象,内部存储的是指向堆内存的指针,你直接发送结构体的话,只会把指针地址发过去,服务端收到的是无效的内存地址,根本拿不到"4G"这个实际字符串内容。
  • 循环条件错误:客户端里的while(count = 0)是赋值操作,不是判断,这会导致循环只执行一次(其实你本来也只需要发一次,完全可以去掉这个循环)。
  • 字节序处理不匹配:你用htons()处理int类型的imsi,但htons()是针对16位短整型的,应该用htonl()处理32位int,服务端接收后要用ntohl()转回来。
  • 未检查recv/send的返回值:这会导致你无法确认数据是否成功发送或接收。

修改后的可运行代码

服务端(Server.cpp)

#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;

// 改用固定大小char数组代替std::string,确保结构体可直接序列化
struct UE {
    char Net[10]; // 预留足够空间存字符串,比如最多9个字符+结束符
    int imsi;
};

int main() {
    UE UE2;
    int sock, cli, receive;
    sockaddr_in server, client;
    socklen_t len; // 用socklen_t代替unsigned int,更规范

    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket creation failed");
        exit(-1);
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(10000);
    server.sin_addr.s_addr = INADDR_ANY;
    memset(&(server.sin_zero), '\0', 8);

    len = sizeof(struct sockaddr_in);
    if((bind(sock, (struct sockaddr *)&server, len)) == -1) {
        perror("Bind failed");
        exit(-1);
    }

    if((listen(sock, 5)) == -1) {
        perror("Listen failed");
        exit(-1);
    }

    cout << "Server listening on port 10000..." << endl;

    while(1) {
        len = sizeof(struct sockaddr_in);
        cli = accept(sock,(struct sockaddr *)&client, &len);
        if(cli == -1) {
            perror("Accept failed");
            continue; // 出错后继续监听,不要直接退出
        }
        cout << "New client connected: " << inet_ntoa(client.sin_addr) << endl;

        // 用cli套接字接收数据,而不是sock
        receive = recv(cli, (void*)&UE2, sizeof(UE2), 0);
        if(receive == -1) {
            perror("Receive failed");
            close(cli);
            continue;
        } else if(receive == 0) {
            cout << "Client disconnected" << endl;
            close(cli);
            continue;
        }

        // 转换字节序,把网络字节序转回主机字节序
        UE2.imsi = ntohl(UE2.imsi);
        cout << "Received struct content:" << endl;
        cout << "Net: " << UE2.Net << endl;
        cout << "IMSI: " << UE2.imsi << endl;

        close(cli);
    }
}

客户端(Client.cpp)

#include <arpa/inet.h>
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;

struct UE {
    char Net[10];
    int imsi;
};

int main(int argc, char *argv[]) {
    if(argc != 3) {
        cout << "Usage: ./client <server_ip> <port>" << endl;
        exit(-1);
    }

    UE UE1;
    // 把字符串复制到char数组里
    strncpy(UE1.Net, "4G", sizeof(UE1.Net)-1);
    UE1.Net[sizeof(UE1.Net)-1] = '\0'; // 确保字符串以结束符结尾
    UE1.imsi = htonl(8649); // 用htonl处理32位int的字节序

    int sock, send_bytes;
    struct sockaddr_in server;

    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket creation failed");
        exit(-1);
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));
    server.sin_addr.s_addr = inet_addr(argv[1]);
    memset(&(server.sin_zero), '\0', 8);

    if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1) {
        perror("Connect failed");
        exit(-1);
    }

    // 发送结构体,检查发送字节数
    send_bytes = send(sock, &UE1, sizeof(UE1), 0);
    if(send_bytes == -1) {
        perror("Send failed");
    } else {
        cout << "Sent " << send_bytes << " bytes to Server:" << endl;
        cout << "Net: " << UE1.Net << ", IMSI: " << ntohl(UE1.imsi) << endl;
    }

    close(sock);
    return 0;
}

关键修改点解释

  • 替换std::string为固定大小char数组:这样结构体的所有数据都存储在连续内存中,发送结构体时会把字符串的实际内容一起发出去,服务端能直接读取到"4G"。
  • 使用正确的套接字通信:服务端必须用accept返回的cli套接字来调用recv,这是和客户端建立的专属连接通道。
  • 字节序处理:网络传输用大端字节序,主机可能是小端,所以用htonl()把int转成网络字节序,服务端用ntohl()转回来,确保跨平台也能正确解析。
  • 返回值检查:每次调用send/recv都检查返回值,能及时发现通信错误,避免无效的后续操作。
  • 修正循环逻辑:客户端去掉了错误的循环,直接发送一次数据,更简洁。

现在你可以编译运行这两个代码:

  • 编译服务端:g++ Server.cpp -o server,运行./server
  • 编译客户端:g++ Client.cpp -o client,运行./client 127.0.0.1 10000

这样就能看到服务端正确接收到结构体内容啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:51:39