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

如何从C客户端向Java服务器发送字节数据?代码排查与方案推荐

问题排查与优化方案

一、代码问题排查

C客户端代码问题

  • 变量拼写错误:定义的变量是langth,但sendto调用中使用的是未初始化的length,导致发送长度异常。
  • 结构体拼写错误:(struct sockeaddr*)&sin中的sockeaddr应为sockaddr,类型不匹配会导致目标地址传递错误。
  • sendto返回值判断逻辑错误:sendto成功时返回发送的字节数,失败时返回-1。原代码if(!sendto(...))仅在发送字节数为0时触发错误打印,实际发送失败(返回-1)时无法被检测到。
  • 发送长度未实时更新:循环外初始化的langth使用了未赋值的header.len,且循环内未根据每次捕获的数据包更新发送长度,应该直接使用header.len作为发送长度。

修正后的C客户端代码:

pcap_t *pcap;
char errbuf[PCAP_ERRBUF_SIZE];
const unsigned char *packet;
struct pcap_pkthdr header;
int offset = 0, sock;

struct sockaddr_in sin = {
            .sin_family = AF_INET,
            .sin_port = htons(5555),
            .sin_addr.s_addr = inet_addr("127.0.0.1"),
            .sin_zero = { 0 }
};

sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if(sock == -1) { // 正确判断socket创建失败
     printf("ERR: socket\n");
     return;
}

pcap = pcap_open_live("wlan0", BUFSIZ, 1, 0, errbuf);

if(!pcap) {
     printf("ERR: %s\n", errbuf);
     return;
}

while ((packet = pcap_next(pcap, &header)) != NULL) {
    int send_len = sendto(sock, packet, header.len, 0, (struct sockaddr*)&sin, sizeof(sin));
    if(send_len == -1) { // 正确判断发送失败
          printf("ERR: %d\n", errno);    
    }
}

Java服务器代码问题

  • DatagramSocket未绑定指定端口:new DatagramSocket()会随机绑定端口,无法监听C客户端发送的5555端口数据,需改为new DatagramSocket(5555)。
  • DatagramPacket初始化错误:接收用的数据包无需指定目标地址和端口,原代码的初始化方式会导致接收逻辑异常,只需传入缓冲区即可。
  • 循环未闭合:原代码while(true)循环缺少闭合},导致编译错误。
  • 未重置数据包长度:每次接收后未重置数据包长度,会导致下次接收受上次数据长度限制。

修正后的Java服务器代码:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.io.IOException;

public class UdpServer {
    public static void main(String[] args) {
        int length = 2048;
        byte[] packet = new byte[length];
        int headerLen = 16;
        DatagramSocket datagramSocket = null;
        try {
            datagramSocket = new DatagramSocket(5555); // 绑定5555监听端口
            DatagramPacket datagramPacket = new DatagramPacket(packet, packet.length); // 仅指定接收缓冲区
            while(true) {
                datagramSocket.receive(datagramPacket);
                System.out.println("packet received.\n");
                byte[] header = new byte[headerLen];
                byte[] data = new byte[datagramPacket.getLength() - headerLen];

                // 用System.arraycopy替代手动循环,更高效
                System.arraycopy(datagramPacket.getData(), 0, header, 0, headerLen);
                System.arraycopy(datagramPacket.getData(), headerLen, data, 0, data.length);
                
                // 重置数据包长度,避免影响下次接收
                datagramPacket.setLength(packet.length);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (datagramSocket != null) {
                datagramSocket.close();
            }
        }
    }
}

二、更优的C与Java数据包传输方案

1. 基于TCP的可靠传输

如果对数据可靠性、有序性有要求,优先选择TCP替代UDP:

  • C客户端:创建SOCK_STREAM类型套接字,通过connect建立连接,使用send/recv收发数据。
  • Java服务器:用ServerSocket监听端口,接受连接后通过Socket的输入输出流读写数据。

2. 自定义结构化数据包协议

无论使用TCP还是UDP,建议定义统一的数据包格式避免粘包/拆包问题,例如:

+----------------+----------------+----------------+
| 魔数(4字节)    | 数据长度(4字节)| 实际数据(n字节)|
+----------------+----------------+----------------+
  • C端用结构体封装数据包,序列化后发送;Java端先读取固定长度的头部,再根据长度读取对应的数据内容。

3. 使用跨语言序列化库

如果不想手动处理数据包格式,可选择成熟的跨语言序列化工具:

  • Protobuf:Google开源的二进制序列化协议,压缩率高、性能优异,原生支持C、Java等多语言。
  • FlatBuffers:Facebook开源的序列化库,无需解析即可直接访问数据,适合性能敏感场景。
  • MsgPack:类JSON的二进制序列化格式,轻量高效,实现成本低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:48:12