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)
{
}
}
}
}