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

如何从Java调用C/C++ TCP/IP服务器并发送指定格式消息?

构造符合要求的TCP/IP服务器注册消息(C语言实现)

我来帮你一步步搞定这个注册消息的构造和发送问题。首先先把给定的结构体定义理清楚,然后再写实际的发送代码,还要注意几个容易踩坑的细节。

一、明确结构体定义(按要求的字节数)

首先把两个结构体完整写出来,注意注释里的字节数要求,这是服务器解析的关键:

// 头部结构体,固定18字节
typedef struct {
    uint32 ui32Synch1;  /* 消息同步标识1,固定值 0x55555555 */
    uint32 ui32Synch2;  /* 消息同步标识2,固定值 0xaaaaaaaa */
    uint16 ui16Version; /* 头部格式版本,固定值 1 */
    uint32 ui32Cmd;     /* 命令码——这里必须用服务器约定的注册命令,比如0x00000001这类,得确认清楚 */
    // 注意:你提供的代码里头部后面有省略号,一定要补全所有字段!
    // 否则结构体总大小会达不到18字节,服务器解析直接错位
    // 比如如果还有预留字段或长度字段,像uint16 ui16Reserved; uint32 ui32Length; 之类的,必须加上
} SPMSifHdr;

// 注册消息结构体,固定62字节(18+20+20+4=62)
struct SPMSifRegisterMsg {
    SPMSifHdr hdr1;       // 18字节的头部
    char szLisence[20];   // 20字节的许可证字符串
    char szApplName[20];  // 20字节的应用名称字符串
    int nRet;             // 4字节的返回值——发送给服务器时一般设为0,服务器回复时会填充结果
};

二、构造并发送消息的示例代码

下面是一个完整的C语言示例,包含socket创建、连接服务器、构造消息、发送的全过程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>

// 先补全头部结构体(假设省略的字段是一个uint16预留字段,确保总大小18字节)
typedef struct {
    uint32_t ui32Synch1;  // 固定0x55555555
    uint32_t ui32Synch2;  // 固定0xaaaaaaaa
    uint16_t ui16Version; // 固定1
    uint32_t ui32Cmd;     // 注册命令码,替换为服务器实际值
    uint16_t ui16Reserved;// 预留字段,设为0(用来凑够18字节:4+4+2+4+4=18)
} SPMSifHdr;

struct SPMSifRegisterMsg {
    SPMSifHdr hdr1;
    char szLisence[20];
    char szApplName[20];
    int nRet;
};

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    struct SPMSifRegisterMsg reg_msg;

    // 1. 创建TCP套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建socket失败");
        exit(EXIT_FAILURE);
    }

    // 2. 设置服务器地址信息
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080); // 替换为服务器实际监听端口
    if (inet_pton(AF_INET, "192.168.1.100", &server_addr.sin_addr) <= 0) { // 替换为服务器IP
        perror("服务器地址无效");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 3. 连接服务器
    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("连接服务器失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 4. 构造注册消息
    memset(&reg_msg, 0, sizeof(reg_msg)); // 先清空整个结构体,避免脏数据

    // 设置头部字段——重点:多字节字段必须转成网络字节序(大端)!
    reg_msg.hdr1.ui32Synch1 = htonl(0x55555555);
    reg_msg.hdr1.ui32Synch2 = htonl(0xaaaaaaaa);
    reg_msg.hdr1.ui16Version = htons(1);
    reg_msg.hdr1.ui32Cmd = htonl(0x00000001); // 这里替换为服务器实际的注册命令码
    reg_msg.hdr1.ui16Reserved = htons(0);

    // 设置许可证和应用名称——注意要填充到20字节,不足的话自动补\0
    strncpy(reg_msg.szLisence, "MY_VALID_LICENSE", sizeof(reg_msg.szLisence)-1);
    strncpy(reg_msg.szApplName, "MY_TEST_APP", sizeof(reg_msg.szApplName)-1);

    // nRet发送时设为0,同样转网络字节序
    reg_msg.nRet = htonl(0);

    // 5. 发送消息
    ssize_t bytes_sent = send(sockfd, &reg_msg, sizeof(reg_msg), 0);
    if (bytes_sent != sizeof(reg_msg)) {
        perror("发送失败或仅发送了部分数据");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("注册消息发送成功!\n");

    // 这里可以添加接收服务器响应的代码,比如:
    // struct SPMSifRegisterMsg resp_msg;
    // ssize_t bytes_recv = recv(sockfd, &resp_msg, sizeof(resp_msg), 0);
    // 然后解析resp_msg.nRet等字段

    close(sockfd);
    return 0;
}

三、必须注意的几个关键细节

  • 字节序问题:这是网络编程最容易踩的坑!所有多字节类型(uint32、uint16、int)都要转换为网络字节序(大端),用htonl()(32位)和htons()(16位)函数。如果客户端是小端系统(比如x86架构),不转换的话服务器解析出来的数值会完全错误。
  • 结构体大小验证:一定要确保SPMSifHdr是18字节,SPMSifRegisterMsg是62字节。可以用printf("Hdr size: %zu\n", sizeof(SPMSifHdr));来打印验证,大小不对的话必须补全头部的省略字段,否则服务器解析会错位。
  • 字符串处理:szLisence和szApplName是固定20字节,用strncpy的时候要留一个字节给\0,如果服务器要求字符串不带\0而是用空格填充,那就要先memset(reg_msg.szLisence, ' ', sizeof(reg_msg.szLisence))再拷贝字符串。
  • 命令码确认:ui32Cmd字段必须是服务器定义的注册命令码,这个一定要和服务器的开发文档或者维护人员确认,填错的话服务器根本识别不了你的消息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:59:11