using System; using System.Text; /** * Created by Tong on 2021/9/22. * link协议粘包拆包 */ public class LinkMessageDecoder { //instance private static LinkMessageDecoder instance = new LinkMessageDecoder(); //getInstance public static LinkMessageDecoder getInstance() { return instance; } /** * 接收数据缓冲区 */ private byte[] byteBuffer; private int position; private byte[] head = System.Text.Encoding.UTF8.GetBytes("Topic:"); public LinkMessageDecoder() { byteBuffer = new byte[1024 * 20];//100K } /// /// 获取内容长度 /// /// /// private int getLenght(string[] topMsgs) { try { for (int i = 0; i < topMsgs.Length; i++) { string topMsg = topMsgs[i].Trim(); if (topMsg.StartsWith("Length:")) { return int.Parse(topMsg.Replace("Length:", "").Trim()); } } } catch (Exception e) { //LogUtils.e("异常数据:" + topMsgs[0] + "\r\n" + topMsgs[1]); return -1; } //找不到长度 return -1; } /// /// 获取主题 /// /// /// private string getTopic(string[] topMsgs) { for (int i = 0; i < topMsgs.Length; i++) { string topMsg = topMsgs[i].Trim(); if (topMsg.StartsWith("Topic:")) { return topMsg.Replace("Topic:", ""); } } //找不到主题 return null; } /** * 获取数据的开始位置 * * @return 数据位的开始索引 */ private int getBodyIndex() { byte r = (byte)'\r'; byte n = (byte)'\n'; for (int i = 0; i < position; i++) { //找出数据内容前面的两个换行 if (3 <= i && byteBuffer[i - 3] == r && byteBuffer[i - 2] == n && byteBuffer[i - 1] == r && byteBuffer[i] == n) { //剩余的数据 return i + 1; } } return -1; } /** * 获取头部数据 * * @return */ private string getHeader() { int bodyIndex = getBodyIndex(); if (bodyIndex < 0) { //没有找到头部数据 return null; } else { return System.Text.Encoding.UTF8.GetString(byteBuffer, 0, bodyIndex); } } /** * 获取数据内容 * * @param lenght * @return */ private byte[] getBody(int index, int lenght) { //是否已经获取完整所有的数据 byte[] bodyBytes = new byte[lenght]; if (index < 0 || position < index + lenght) { //当前数据还没有接收完成 return null; } for (int i = 0; i < bodyBytes.Length; i++) { bodyBytes[i] = byteBuffer[index + i]; } return bodyBytes; } /** * 移除可能存在的无效数据 */ private void removeInVoidBytes() { int index = 0; bool isMatch = false; for (; index < position - head.Length; index++) { isMatch = true; for (int j = 0, k = 0; j < head.Length; j++, k++) { if (head[j] != byteBuffer[index + k]) { isMatch = false; break; } } if (isMatch) { break; } } if (0 < index && isMatch) { int endIndex = position; position = 0; //byteBuffer.clear(); for (int i = index; i < endIndex; i++) { byteBuffer[position++] = byteBuffer[i]; } } } /** * 移除到指定位置前面的数据 * * @param position 指定位置 */ private void remove(int index) { int endIndex = position; position = 0; //byteBuffer.clear(); for (int i = index; i < endIndex; i++) { byteBuffer[position++] = byteBuffer[i]; } } public void Decoder(byte[] bytes, Action action) { lock (instance) { try { if (null == bytes) { return; } System.Array.Copy(bytes, 0, byteBuffer, position, bytes.Length); position += bytes.Length; //如果多条命令打包在一条数据中,都需要处理完 while (true) { removeInVoidBytes();//移除可能存在的无效数据 //头部数据 string header = getHeader(); if (header == null) { break; } string[] topMsgs = header.Split("\r\n"); string topic = getTopic(topMsgs); int lenght = getLenght(topMsgs); if (topic == null || lenght <= 0) { //获取不到主题或者头部数据还没有接收完成 break; } int bodyIndex = getBodyIndex(); //是否已经获取完整所有的数据 byte[] body = getBody(bodyIndex, lenght); if (body == null) { //当前数据还没有接收完成 break; } remove(bodyIndex + lenght); action?.Invoke(topic, body); } } catch (Exception ee) { } } } }