浅谈Java之Socket粘包处理

一、基本介绍

        Java Socket编程中,粘包和半包问题是常见的问题,主要原因是TCP协议是基于流的协议,数据在传输过程中是连续的,没有明确的界限。

二、常见的解决方案

1、固定长度:发送方和接收方约定一个固定的大小来读取数据,如果数据不足这个长度,则用空格或其他填充字符补齐。这种方法简单,但不够灵活,可能会造成空间浪费。

2、分隔符:发送方在每个数据包的末尾添加一个特定的分隔符,接收方通过识别这个分隔符来确定一个数据包的结束。这种方法适用于数据包内容中不包含分隔符的情况,否则需要对数据进行编码和解码处理。

3、消息头和消息体:在TCP协议的基础上封装一层数据请求协议,将数据包封装成数据头(存储数据正文大小)+ 数据正文的形式。这样在服务端就可以知道每个数据包的具体长度,从而解决半包和粘包的问题。这种方法需要在发送和接收数据时都添加额外的处理逻辑,但能够有效地解决粘包和半包问题。

在实际应用中,第三种方法是最推荐的解决方案,因为它既灵活又能够有效地解决粘包和半包问题。具体实现时,可以在发送数据前,先发送一个包含数据长度的消息头,然后发送实际的数据内容。接收方先读取消息头,获取数据长度,再根据这个长度读取相应的数据内容。

三、简单示例

class SocketPacket {
    static final int HEAD_SIZE = 4; // 消息头长度为4个字节

    public byte[] toBytes(String context) {
        byte[] bodyByte = context.getBytes();
        int bodyByteLength = bodyByte.length;
        byte[] result = new byte[HEAD_SIZE + bodyByteLength];
        // 将消息体长度写入消息头
        result[0] = (byte) (bodyByteLength >> 24);
        result[1] = (byte) (bodyByteLength >> 16);
        result[2] = (byte) (bodyByteLength >> 8);
        result[3] = (byte) (bodyByteLength);
        // 将消息体写入结果数组
        System.arraycopy(bodyByte, 0, result, HEAD_SIZE, bodyByteLength);
        return result;
    }

    public int getHeader(InputStream inputStream) throws IOException {
        byte[] bytes = new byte[HEAD_SIZE];
        inputStream.read(bytes, 0, HEAD_SIZE);
        int length = ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
        return length;
    }
}

在服务器端,可以这样读取数据:

SocketPacket socketPacket = new SocketPacket();
try (InputStream inputStream = clientSocket.getInputStream()) {
    while (true) {
        int bodyLength = socketPacket.getHeader(inputStream);
        byte[] bodyByte = new byte[bodyLength];
        inputStream.read(bodyByte);
        System.out.println("接收到客户端的信息: " + new String(bodyByte));
    }
}

在客户端,可以这样发送数据:

SocketPacket socketPacket = new SocketPacket();
try (OutputStream outputStream = socket.getOutputStream()) {
    for (int i = 0; i < 10; i++) {
        String msg = "Hi,Java.";
        byte[] bytes = socketPacket.toBytes(msg);
        outputStream.write(bytes);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CnLg.NJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值