Java TLV tcp粘包处理

mac2024-05-29  42

TLV: type length value,用来处理tcp粘包的一种解决办法。在发送tcp包时,用type标明数据类型,length标明数据长度,value代表要发送的数据。

type、length:一般用2到4个字节表示。

-----type(4bytes)------|--------length(4bytes)--------|-------value------

//tcp数据写入、读取处理 package net; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; public class Tlv { DataInputStream dis = null; DataOutputStream dos = null; Socket s = null; public Tlv(Socket s) { this.s = s; try { dos = new DataOutputStream(s.getOutputStream()); dis = new DataInputStream(s.getInputStream()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } public void writeMsg(String msg, int type) { byte[] MsgB = msg.getBytes(StandardCharsets.UTF_8); int len = MsgB.length; // byte[] by = new byte[4]; ByteBuffer bb = ByteBuffer.wrap(by); bb.order(ByteOrder.LITTLE_ENDIAN);// 这里使用小端序 byte[] SendMsg = new byte[4 + 4 + len]; // int(type) + int(len) + msg.len int i = 0; // 写入类型 bb.asIntBuffer().put(type); for (i = 0; i < by.length; i++) { SendMsg[i] = by[i]; } bb.asIntBuffer().put(0);// 清空 // 写入长度 bb.asIntBuffer().put(len);// int j = i; for (int k = 0; k < by.length; j++, k++) { SendMsg[j] = by[k]; } // 写入消息 int n = j; for (int k = 0; k < MsgB.length; k++, n++) { SendMsg[n] = MsgB[k]; } try { dos.write(SendMsg); dos.flush(); } catch (Exception e) { // TODO: handle exception System.out.println("写入消息错误"); e.printStackTrace(); } } public Msg readMsg() { byte[] typeB = new byte[4]; byte[] lenB = new byte[4]; try { Msg msg = new Msg(); dis.readFully(typeB); msg.type = LITTLEENDIAN(typeB); dis.readFully(lenB); msg.len = LITTLEENDIAN(lenB); byte[] rmsg = new byte[msg.len]; dis.readFully(rmsg); msg.msg = rmsg; // System.out.println("========读取到的消息为:" + (new String(rmsg))); return msg; } catch (Exception e) { // TODO: handle exception System.out.println("读取数据错误"); e.printStackTrace(); } return null; } public static int BIGENDIAN(byte[] b) { int t = 0; if (b.length != 4) { return 0; } t = 0xff & b[0] << 24; t = t | (0xff & b[1]) << 16; t = t | (0xff & b[2]) << 8; t = t | (0xff & b[3]); return t; } public static int LITTLEENDIAN(byte[] b) { int t = 0; if (b.length != 4) { return 0; } t = 0xff & b[0]; t = t | (0xff & b[1]) << 8; t = t | (0xff & b[2]) << 16; t = t | (0xff & b[3]) << 24; return t; } public void close() { try { if (dis != null) { dis.close(); } if (dos != null) { dos.close(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } //msg package net; public class Msg { int type = 0; int len = 0; byte[] msg = null; public byte[] getmsg() { // TODO 自动生成的方法存根 return msg; } public int gettype() { // TODO 自动生成的方法存根 return type; } public int getlen() { // TODO 自动生成的方法存根 return len; } }

客户端代码

package client; import java.net.Socket; import java.util.concurrent.TimeUnit; import net.Msg; import net.Tlv; public class Client implements Runnable { private Tlv tlv = null; Socket s = null; /** * @param args */ public static void main(String args[]) { try { Client c = new Client(); Thread t = new Thread(c.new ShutdownHook(), "ShutdownHook-Thread"); Runtime.getRuntime().addShutdownHook(t); Socket s = new Socket("127.0.0.1", 3333); c.tlv = new Tlv(s); new Thread(c).start(); for (int i = 0; i < 20; i++) { String str = i + "_" + "Hello java world!!!"; c.tlv.writeMsg(str, 1); Thread.sleep(1 * 1000); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } @Override public void run() { Msg msg = null; while (true) { msg = tlv.readMsg(); System.out.println("read a msg:" + (new String(msg.getmsg()))); } } class ShutdownHook implements Runnable {//安全退出方法 @Override public void run() { System.out.println("ShutdownHook execute start..."); try { tlv.close(); TimeUnit.SECONDS.sleep(10);// 模拟应用进程退出前的处理操作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ShutdownHook execute end..."); } } }

服务端代码

package server; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; import net.Msg; import net.Tlv; public class Server { ServerSocket ss = null; List<SC> list = new ArrayList<SC>(); // 保存客户端线程类 public static void main(String[] args) { System.out.println("server started"); new Server().start(); } void start() { try { ss = new ServerSocket(3333); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } try { while (true) { Socket s = ss.accept(); // 接收客户端 SC sc = new SC(s); new Thread(sc).start(); list.add(sc); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } class SC implements Runnable { Socket s = null; Tlv tlv = null; public SC(Socket s) { this.s = s; tlv = new Tlv(s); } @Override public void run() { // TODO 自动生成的方法存根 while (true) { Msg msg = tlv.readMsg(); System.out.println("recived a message:" + (new String(msg.getmsg()))); tlv.writeMsg("recived a message", 2); } } void close() { tlv.close(); try { if (s != null) { s.close(); } } catch (Exception e) { // TODO: handle exception } } } void close() { try { if (ss != null) { ss.close(); } for (int i = 0; i < list.size(); i++) { list.get(i).close(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } class shutdownhook implements Runnable {//安全退出方法 @Override public void run() { // TODO 自动生成的方法存根 close(); System.out.println("server closed"); } } }
最新回复(0)