From d839ff96ad59ec51c30f3ad8ee4446d36c3f2476 Mon Sep 17 00:00:00 2001 From: qmstyle Date: Sat, 22 Feb 2025 18:13:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=B0=81=E8=A3=85=202025?= =?UTF-8?q?=E5=B9=B42=E6=9C=8822=E6=97=A518:13:31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../java/com/zhangmeng/service/DataPack.java | 18 ++ .../java/com/zhangmeng/service/Message.java | 24 +++ .../zhangmeng/service/impl/DataPackImpl.java | 44 +++++ .../zhangmeng/service/impl/MessageImpl.java | 45 +++++ .../com/zhangmeng/utils/ByteBufferUtil.java | 185 ++++++++++++++++++ 6 files changed, 322 insertions(+) create mode 100644 src/main/java/com/zhangmeng/service/DataPack.java create mode 100644 src/main/java/com/zhangmeng/service/Message.java create mode 100644 src/main/java/com/zhangmeng/service/impl/DataPackImpl.java create mode 100644 src/main/java/com/zhangmeng/service/impl/MessageImpl.java create mode 100644 src/main/java/com/zhangmeng/utils/ByteBufferUtil.java diff --git a/pom.xml b/pom.xml index b172fed..5e1b286 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,12 @@ 5.8.27 + + io.netty + netty-all + 4.1.72.Final + + junit junit diff --git a/src/main/java/com/zhangmeng/service/DataPack.java b/src/main/java/com/zhangmeng/service/DataPack.java new file mode 100644 index 0000000..6b51be2 --- /dev/null +++ b/src/main/java/com/zhangmeng/service/DataPack.java @@ -0,0 +1,18 @@ +package com.zhangmeng.service; + +/** + * 封包数据和拆包数据 + * 直接面向TCP连接中的数据流,为传输数据添加头部信息,用于处理TCP粘包问题。 + * + * @author zm + * @date 2025/2/22 17:33 + * @version: 1.0 + */ +public interface DataPack { + public int GetHeadLen(); //获取包头长度方法 + + public byte[] Pack(Message msg); //封包方法 + + public Message Unpack(byte[] data); //拆包方法 + +} diff --git a/src/main/java/com/zhangmeng/service/Message.java b/src/main/java/com/zhangmeng/service/Message.java new file mode 100644 index 0000000..e0f550c --- /dev/null +++ b/src/main/java/com/zhangmeng/service/Message.java @@ -0,0 +1,24 @@ +package com.zhangmeng.service; + +/** + * 将请求的一个消息封装到message中,定义抽象层接口 + * + * @author zm + * @date 2025/2/22 17:26 + * @version: 1.0 + */ +public interface Message { + + public int GetDataLen(); //获取消息数据段长度 + + public int GetMsgId(); //获取消息ID + + public byte[] GetData(); //获取消息内容 + + public void SetMsgId(int msgId); //设计消息ID + + public void SetData(byte[] bytes); //设计消息内容 + + public void SetDataLen(int length); //设置消息数据段长度 + +} diff --git a/src/main/java/com/zhangmeng/service/impl/DataPackImpl.java b/src/main/java/com/zhangmeng/service/impl/DataPackImpl.java new file mode 100644 index 0000000..de8d6de --- /dev/null +++ b/src/main/java/com/zhangmeng/service/impl/DataPackImpl.java @@ -0,0 +1,44 @@ +package com.zhangmeng.service.impl; + +import com.zhangmeng.service.DataPack; +import com.zhangmeng.service.Message; + + +import java.nio.ByteBuffer; + +/** + * @author zm + * @date 2025/2/22 17:36 + * @version: 1.0 + */ +public class DataPackImpl implements DataPack { + + @Override + public int GetHeadLen() { + return 8; + } + + @Override + public byte[] Pack(Message msg) { + + ByteBuffer byteBuffer = ByteBuffer.allocate(16); + + //写dataLen + byteBuffer.putInt(msg.GetDataLen()); + + //写msgID + byteBuffer.putInt(msg.GetMsgId()); + + //写data + byteBuffer.put(msg.GetData()); + + + byte[] data = byteBuffer.array(); + return data; + } + + @Override + public Message Unpack(byte[] data) { + return null; + } +} diff --git a/src/main/java/com/zhangmeng/service/impl/MessageImpl.java b/src/main/java/com/zhangmeng/service/impl/MessageImpl.java new file mode 100644 index 0000000..1524af5 --- /dev/null +++ b/src/main/java/com/zhangmeng/service/impl/MessageImpl.java @@ -0,0 +1,45 @@ +package com.zhangmeng.service.impl; + +import com.zhangmeng.service.Message; + +/** + * @author zm + * @date 2025/2/22 17:31 + * @version: 1.0 + */ +public class MessageImpl implements Message { + + private int Id; //消息的ID + private int DataLen; //消息的长度 + private byte[] Data;//消息的内容 + + @Override + public int GetDataLen() { + return this.DataLen; + } + + @Override + public int GetMsgId() { + return this.Id; + } + + @Override + public byte[] GetData() { + return this.Data; + } + + @Override + public void SetMsgId(int msgId) { + this.Id = msgId; + } + + @Override + public void SetData(byte[] bytes) { + this.Data = bytes; + } + + @Override + public void SetDataLen(int length) { + this.DataLen = length; + } +} diff --git a/src/main/java/com/zhangmeng/utils/ByteBufferUtil.java b/src/main/java/com/zhangmeng/utils/ByteBufferUtil.java new file mode 100644 index 0000000..c1dc222 --- /dev/null +++ b/src/main/java/com/zhangmeng/utils/ByteBufferUtil.java @@ -0,0 +1,185 @@ +package com.zhangmeng.utils; + + +import io.netty.util.internal.StringUtil; + +import java.nio.ByteBuffer; + +import static io.netty.util.internal.MathUtil.isOutOfBounds; +import static io.netty.util.internal.StringUtil.NEWLINE; + + +/** + * @author zm + * @date 2025/2/22 17:44 + * @version: 1.0 + */ +public class ByteBufferUtil { + private static final char[] BYTE2CHAR = new char[256]; + private static final char[] HEXDUMP_TABLE = new char[256 * 4]; + private static final String[] HEXPADDING = new String[16]; + private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4]; + private static final String[] BYTE2HEX = new String[256]; + private static final String[] BYTEPADDING = new String[16]; + + static { + final char[] DIGITS = "0123456789abcdef".toCharArray(); + for (int i = 0; i < 256; i++) { + HEXDUMP_TABLE[i << 1] = DIGITS[i >>> 4 & 0x0F]; + HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F]; + } + + int i; + + // Generate the lookup table for hex dump paddings + for (i = 0; i < HEXPADDING.length; i++) { + int padding = HEXPADDING.length - i; + StringBuilder buf = new StringBuilder(padding * 3); + for (int j = 0; j < padding; j++) { + buf.append(" "); + } + HEXPADDING[i] = buf.toString(); + } + + // Generate the lookup table for the start-offset header in each row (up to 64KiB). + for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i++) { + StringBuilder buf = new StringBuilder(12); + buf.append(NEWLINE); + buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L)); + buf.setCharAt(buf.length() - 9, '|'); + buf.append('|'); + HEXDUMP_ROWPREFIXES[i] = buf.toString(); + } + + // Generate the lookup table for byte-to-hex-dump conversion + for (i = 0; i < BYTE2HEX.length; i++) { + BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i); + } + + // Generate the lookup table for byte dump paddings + for (i = 0; i < BYTEPADDING.length; i++) { + int padding = BYTEPADDING.length - i; + StringBuilder buf = new StringBuilder(padding); + for (int j = 0; j < padding; j++) { + buf.append(' '); + } + BYTEPADDING[i] = buf.toString(); + } + + // Generate the lookup table for byte-to-char conversion + for (i = 0; i < BYTE2CHAR.length; i++) { + if (i <= 0x1f || i >= 0x7f) { + BYTE2CHAR[i] = '.'; + } else { + BYTE2CHAR[i] = (char) i; + } + } + } + + /** + * 打印所有内容 + * @param buffer + */ + public static void debugAll(ByteBuffer buffer) { + int oldlimit = buffer.limit(); + buffer.limit(buffer.capacity()); + StringBuilder origin = new StringBuilder(256); + appendPrettyHexDump(origin, buffer, 0, buffer.capacity()); + System.out.println("+--------+-------------------- all ------------------------+----------------+"); + System.out.printf("position: [%d], limit: [%d]\n", buffer.position(), oldlimit); + System.out.println(origin); + buffer.limit(oldlimit); + } + + /** + * 打印可读取内容 + * @param buffer + */ + public static void debugRead(ByteBuffer buffer) { + StringBuilder builder = new StringBuilder(256); + appendPrettyHexDump(builder, buffer, buffer.position(), buffer.limit() - buffer.position()); + System.out.println("+--------+-------------------- read -----------------------+----------------+"); + System.out.printf("position: [%d], limit: [%d]\n", buffer.position(), buffer.limit()); + System.out.println(builder); + } + + private static void appendPrettyHexDump(StringBuilder dump, ByteBuffer buf, int offset, int length) { + if (isOutOfBounds(offset, length, buf.capacity())) { + throw new IndexOutOfBoundsException( + "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length + + ") <= " + "buf.capacity(" + buf.capacity() + ')'); + } + if (length == 0) { + return; + } + dump.append( + " +-------------------------------------------------+" + + NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" + + NEWLINE + "+--------+-------------------------------------------------+----------------+"); + + final int startIndex = offset; + final int fullRows = length >>> 4; + final int remainder = length & 0xF; + + // Dump the rows which have 16 bytes. + for (int row = 0; row < fullRows; row++) { + int rowStartIndex = (row << 4) + startIndex; + + // Per-row prefix. + appendHexDumpRowPrefix(dump, row, rowStartIndex); + + // Hex dump + int rowEndIndex = rowStartIndex + 16; + for (int j = rowStartIndex; j < rowEndIndex; j++) { + dump.append(BYTE2HEX[getUnsignedByte(buf, j)]); + } + dump.append(" |"); + + // ASCII dump + for (int j = rowStartIndex; j < rowEndIndex; j++) { + dump.append(BYTE2CHAR[getUnsignedByte(buf, j)]); + } + dump.append('|'); + } + + // Dump the last row which has less than 16 bytes. + if (remainder != 0) { + int rowStartIndex = (fullRows << 4) + startIndex; + appendHexDumpRowPrefix(dump, fullRows, rowStartIndex); + + // Hex dump + int rowEndIndex = rowStartIndex + remainder; + for (int j = rowStartIndex; j < rowEndIndex; j++) { + dump.append(BYTE2HEX[getUnsignedByte(buf, j)]); + } + dump.append(HEXPADDING[remainder]); + dump.append(" |"); + + // Ascii dump + for (int j = rowStartIndex; j < rowEndIndex; j++) { + dump.append(BYTE2CHAR[getUnsignedByte(buf, j)]); + } + dump.append(BYTEPADDING[remainder]); + dump.append('|'); + } + + dump.append(NEWLINE + + "+--------+-------------------------------------------------+----------------+"); + } + + private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) { + if (row < HEXDUMP_ROWPREFIXES.length) { + dump.append(HEXDUMP_ROWPREFIXES[row]); + } else { + dump.append(NEWLINE); + dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L)); + dump.setCharAt(dump.length() - 9, '|'); + dump.append('|'); + } + } + + public static short getUnsignedByte(ByteBuffer buffer, int index) { + return (short) (buffer.get(index) & 0xFF); + } +} +