javasocket编程解决粘包和丢包问题

     2022-04-30     720

关键词:

##socket 丢包粘包解决方式

采用固定头部长度(一般为4个字节),包头保存的是包体的长度

header+body

包头+包体

 

思路是:先读出一个包头,得到包体的长度,解析出包体

 

public class SocketServer {
    public static void main(String args[]) {
        ServerSocket serverSocket;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(8089));
            System.out.println("启动服务端~");
            while (true) {
                Socket socket = serverSocket.accept();
                new ReceiveThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class ReceiveThread extends Thread {
        public static final int PACKET_HEAD_LENGTH = 4;// 包头长度
        private Socket socket;
        private volatile byte[] bytes = new byte[0];

        public ReceiveThread(Socket socket) {
            this.socket = socket;
        }

        //将b数组 下标从begin到end-1的值追加到a数组的后面,并返回
        public byte[] mergebyte(byte[] a, byte[] b, int begin, int end) {
            byte[] add = new byte[a.length + end - begin];
            int i = 0;
            for (i = 0; i < a.length; i++) {
                add[i] = a[i];
            }
            for (int k = begin; k < end; k++, i++) {
                add[i] = b[k];
            }
            return add;
        }

        @Override
        public void run() {
            int count = 0;
            while (true) {
                try {
                    InputStream reader = socket.getInputStream();
                    {  //这里可以保证正好读取到4个字节的包头
                        if (bytes.length < PACKET_HEAD_LENGTH) { //【第一次进来,或者经过一次循环bytes的长度被置为0】
                            byte[] head = new byte[PACKET_HEAD_LENGTH - bytes.length];
                            int couter = reader.read(head);
                            if (couter < 0) {
                                continue;
                            }
                            bytes = mergebyte(bytes, head, 0, couter);
                            if (couter < PACKET_HEAD_LENGTH) {
                                continue;
                            }
                        }
                    }
                    
                    // 取出包体长度
                    byte[] temp = new byte[0];
                    temp = mergebyte(temp, bytes, 0, PACKET_HEAD_LENGTH);
                    int bodylength = ByteUtil.byteArrayToInt(temp);// 包体长度
                    
                    //完整读取一个包
                    if (bytes.length < bodylength + PACKET_HEAD_LENGTH) {// 不够一个包
                        byte[] body = new byte[bodylength + PACKET_HEAD_LENGTH - bytes.length];// 剩下应该读的字节(凑一个包)
                        int couter = reader.read(body);
                        if (couter < 0) {
                            continue;
                        }
                        bytes = mergebyte(bytes, body, 0, couter);
                        if (couter < body.length) {
                            continue;
                        }
                    }
                    
                    //把包体的内容读取出来
                    byte[] body = new byte[0];
                    body = mergebyte(body, bytes, PACKET_HEAD_LENGTH, bytes.length);
                    count++;
                    System.out.println("server receive body:  " + count + new String(body));
                    //为读取下一个包将数组长度重置为空数组,长度为0
                    bytes = new byte[0];
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

 

public class ClientSocket {
    public static void main(String args[]) throws IOException {
        System.out.println("启动客户端~");
        Socket clientSocket = new Socket();
        clientSocket.connect(new InetSocketAddress(8089));
        new SendThread(clientSocket).start();
 
    }
 
    static class SendThread extends Thread {
        Socket socket;
        public SendThread(Socket socket) {
            this.socket = socket;
        }
 
        @Override
        public void run() {
            String reqMessage = "HelloWorl !  from clientsocket this is test half packages!";
            for (int i = 0; i < 100; i++) {
                sendPacket(reqMessage+ "u "+ i);
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
 
        }
 
        public void sendPacket(String message) {
            byte[] contentBytes = message.getBytes();// 包体内容
            int contentlength = contentBytes.length;// 包体长度
            byte[] headbytes = ByteUtil.intToByteArray(contentlength);// 包头字节数组
            byte[] bytes = new byte[headbytes.length + contentlength];// 包=包头+包体
            int i = 0;
            for (i = 0; i < headbytes.length; i++) {// 包头
                bytes[i] = headbytes[i];
            }
            for (int j = i, k = 0; k < contentlength; k++, j++) {// 包体
                bytes[j] = contentBytes[k];
            }
            try {
                OutputStream writer = socket.getOutputStream();
                writer.write(bytes);
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
}

 

public class ByteUtil {

    public static void main(String[] args) {
        byte[] res =  intToByteArray(10);
        System.out.println(byteArrayToInt(res));
        
    }
    
    public static byte[] intToByteArray(int i) {  
        byte[] result = new byte[4];  
        // 由高位到低位  
        result[0] = (byte) ((i >> 24) & 0xFF);  
        result[1] = (byte) ((i >> 16) & 0xFF);  
        result[2] = (byte) ((i >> 8) & 0xFF);  
        result[3] = (byte) (i & 0xFF);  
        return result;  
    } 
    
    public static int byteArrayToInt(byte[] bytes) {  
        int value = 0;  
        // 由高位到低位  
        for (int i = 0; i < 4; i++) {  
            int shift = (4 - 1 - i) * 8;  
            value += (bytes[i] & 0x000000FF) << shift;// 往高位游  
        }  
        return value;  
    } 
}

 

转自: https://blog.csdn.net/nongfuyumin/article/details/78298380?utm_source=blogxgwz5

 

解决粘包和拆包问题(代码片段)

解决粘包和拆包问题 上一篇我们介绍了如果使用Netty来开发一个简单的服务端和客户端,接下来我们来讨论如何使用解码器来解决TCP的粘包和拆包问题我们知道,TCP是以一种流的方式来进行网络转播的,当tcp三次握手简历通... 查看详情

详解啥是tcp粘包和拆包现象并演示netty是如何解决的

...后再通过一个Netty的demo来解决这个问题。具体内容如下TCP编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输的时候,在网络中的byte其实就像是河水,TCP就像一个搬运工,将这流水从一端转送到另一端,... 查看详情

netty解决粘包和拆包问题的四种方案(代码片段)

 在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接。由于微服务往对方发送信息的时候,所有的请求都是使... 查看详情

socket编程粘包和半包问题的及处理

一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系。粘包为x.5个包半包为0.5个包由于网络原因一次可能会来0.5/1/2/2.5/。。。。个包当接... 查看详情

java网络编程——粘包拆包出现的原因及解决方式(代码片段)

在基于TCP协议的网络编程中,不可避免地都会遇到粘包和拆包的问题。什么是粘包和拆包?先来看个例子,还是上篇文章《Java网络编程——NIO的阻塞IO模式、非阻塞IO模式、IO多路复用模式的使用》中“IO多路复用模式... 查看详情

java网络编程——粘包拆包出现的原因及解决方式(代码片段)

在基于TCP协议的网络编程中,不可避免地都会遇到粘包和拆包的问题。什么是粘包和拆包?先来看个例子,还是上篇文章《Java网络编程——NIO的阻塞IO模式、非阻塞IO模式、IO多路复用模式的使用》中“IO多路复用模式... 查看详情

粘包和半包有了解过吗?netty是如何解决这个问题的(代码片段)

...了解一下什么是粘包,什么是半包,以及如何去解决。粘包:故名思意就是客户 查看详情

粘包和半包有了解过吗?netty是如何解决这个问题的(代码片段)

...了解一下什么是粘包,什么是半包,以及如何去解决。粘包:故名思意就是客户 查看详情

网络i/o编程模型21netty的粘包和拆包问题的解决方案(代码片段)

一问题背景描述1.1问题描述tcp是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务端)都要有一一成对的socket;客户端为了每次更有效的发送更多的数据给对方,使用了优化方法(Nagle算... 查看详情

netty解决粘包和拆包问题的四种方案(代码片段)

 在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接。由于微服务往对方发送信息的时候,所有的请求都是使... 查看详情

tcp粘包和拆包及解决方案(代码片段)

...和拆包基本介绍2.TCP粘包和拆包现象实例3.TCP粘包和拆包解决方案 4.具体实例1. TCP粘包和拆包基本介绍TCP 是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的 socket&#x... 查看详情

java网络编程——粘包拆包出现的原因及解决方式(代码片段)

在基于TCP协议的网络编程中,不可避免地都会遇到粘包和拆包的问题。什么是粘包和拆包?先来看个例子,还是上篇文章《Java网络编程——NIO的阻塞IO模式、非阻塞IO模式、IO多路复用模式的使用》中“IO多路复用模式... 查看详情

java网络编程——粘包拆包出现的原因及解决方式(代码片段)

在基于TCP协议的网络编程中,不可避免地都会遇到粘包和拆包的问题。什么是粘包和拆包?先来看个例子,还是上篇文章《Java网络编程——NIO的阻塞IO模式、非阻塞IO模式、IO多路复用模式的使用》中“IO多路复用模式... 查看详情

tcp粘包和拆包

...个数据包粘在一起的情况,这就是TCP协议中经常会遇到的粘包以及拆包的问题。传输层的UDP协议是否会发生粘包或者拆包问题?不会。UDP是基于报文发送的,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的... 查看详情

用iperf3测试网络带宽和丢包

参考技术A用iperf3测试网络带宽和丢包具体步骤如下: 查看详情

tcp粘包拆包基本解决方案

...粘包和拆包的现象,Netty对此问题提供了相对比较丰富的解决方案 Netty提供了几个常用的解码器,帮助我们解决这些问题,其实上述的粘包和拆包的问题,归根结底的解决方案就是发送端给远程端一个标记,告诉远程端,每... 查看详情

tcp粘包拆包原因与解决方案

文章目录TCP粘包和拆包问题背景举例说明产生原因解决方案思考:UDP会不会产生粘包问题呢?TCP粘包和拆包问题背景TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据。TCP作为传输层协议并不了解... 查看详情

tcp粘包拆包原因与解决方案

文章目录TCP粘包和拆包问题背景举例说明产生原因解决方案思考:UDP会不会产生粘包问题呢?TCP粘包和拆包问题背景TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据。TCP作为传输层协议并不了解... 查看详情