|
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
|
}
|
|
/// <summary>
|
/// 获取内容长度
|
/// </summary>
|
/// <param name="topMsgs"></param>
|
/// <returns></returns>
|
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;
|
}
|
|
/// <summary>
|
/// 获取主题
|
/// </summary>
|
/// <param name="topMsgs"></param>
|
/// <returns></returns>
|
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<string, byte[]> 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)
|
{
|
|
}
|
}
|
}
|
}
|