##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;
- }
- }
来源: http://www.bubuko.com/infodetail-2982146.html