1. 程式人生 > >java socket編程解決粘包和丟包問題

java socket編程解決粘包和丟包問題

cat exceptio nal end ddr exc gen main socket

##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

java socket編程解決粘包和丟包問題