100元话费+500莫元咨询TCP 黏包服务器怎么处理的问题

2020-01-01 17:38发布

本帖最后由 lindabell 于 2017-1-12 16:42 编辑

事情是这样的,我做了一台设备可以通过app控制,也可以上报温湿度等信息的;使用透传的WIFI模块。
设备从关机到开机会发生很多状态变化,都会上传这些状态;通过串口发送到WIFI模块,然后到服务器。
在服务器接收那边就会出现黏包的现象,由于黏包服务器处理起来非常耗时,应该是3~4s的数据到了数据库看居然花了26s左右。

另外我数据的格式是这样的 55AA+MAC+len+CRC8,黏包就是多包数据被TCP封成一个包了。

希望做个服务器 (要专业做服务器的,不是专业的意见不接受)的坛友,给个意见这样的黏包服务器能不能处理,怎样处理?

注:我是做单片机软件的对服务器一点不懂,但是我需要的是专业的回答,另外回答的不错的;可能还会付费咨询更加详细的,报酬方面可谈。


修改:增加到200元话费,高手希望提示一下
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
88条回答
STT
1楼-- · 2020-01-11 06:53
我们做的是7e开始 7ej结束   遇到7e转义  7e==>7d 5e    7d==>7d 5d   两个7e间就是数据
lindabell
2楼-- · 2020-01-11 12:23
STT 发表于 2017-1-13 16:34
我们做的是7e开始 7ej结束   遇到7e转义  7e==>7d 5e    7d==>7d 5d   两个7e间就是数据 ...

这种协议我也写过,汽车行业里的一个国标协议。
服务器人能力不行,这个他肯定也搞不出来;最好搞个json给他就满意了。
lindabell
3楼-- · 2020-01-11 12:23
styleno1 发表于 2017-1-13 16:18
Modbus over TCP文档是这样指导的:

印象中modbus是靠时间间隔来区分帧的,所以会这样写。
kevin_ares
4楼-- · 2020-01-11 12:56
55AA+MAC+len+CRC8
随便写个函数截断就行了
其实不你只是要解决粘包,还要解决一个数据包分两次收到
落叶知秋
5楼-- · 2020-01-11 15:07
 精彩回答 2  元偷偷看……
huchunlei
6楼-- · 2020-01-11 17:43
本帖最后由 huchunlei 于 2017-1-13 21:39 编辑

楼主最近做的事跟我做的类似,我也是做单片机的,但是服务器没人写,我只有自己写了。  我用的是 UDP,设备端用的是 透传的 GPRS DTU, 设备传过来的数据 会发生, 一包分成2包, 或者多包和并在一起。  所以,我这个数据处理也有你这个问题。  不过花了几天时间,问题基本上解决了。
大体思路如下:

1、接收的数据进行初步的判断,同一个IP地址发过来的数据进行连接。
2、将连接后的数据进行识别,也就是最笨的办法,从前往后遍历,遇到包头,就按照协议规则去计算验证码,验证码正确,就把这部分数据提取出来。 然后前面多出来的数据是无效数据, 而后面多出来的数据要留着,需要跟新接收过来的数据包进行连接。
3、对提取出来的数据进行处理。

我的C# 代码如下, 供你参考:(声明一下,我是做单片机的,上位机我非专业人事,所以代码风格很烂,仅供参考)

1、数据处理代码:(处理代码是单独一个线程运行的,所以里面是个大的死循环)

  1. private void ServiceProcess()
  2.         {
  3.             byte[] PendingDataBuffer = null;    //待处理流数据缓存
  4.             IPEndPoint PendingRemote = null;    //待处理流数据的来源地址

  5.             while (true)
  6.             {
  7.                 //读取并缓存原始数据
  8.                 List<UdpReceiveDataStruct> ReceiveOrgList = ServiceUdpClient.GetReceiveData();
  9.                 while (ReceiveOrgList.Count > 0)
  10.                 {
  11.                     UdpReceiveDataStruct ReceiveOrg = ReceiveOrgList[0];
  12.                     lock (UdpReceiveOrgListLocker)
  13.                     {
  14.                         UdpReceiveOrgList.Add(ReceiveOrg);
  15.                         ReceiveOrgList.RemoveAt(0);
  16.                     }
  17.                 }

  18.                 //由于原始数据可能存在错误的分包、组包,需要对数据进行识别并缓存有效数据
  19.                 while (UdpReceiveOrgList.Count > 0)
  20.                 {
  21.                     UdpReceiveDataStruct ReceiveOrg;

  22.                     //通信总数+1
  23.                     lock (CommunicatorStateLocker)
  24.                     {
  25.                         CommunicatorState.CommunicationTotalCount++;
  26.                     }

  27.                     //取出一条原始数据
  28.                     lock (UdpReceiveOrgListLocker)
  29.                     {
  30.                         ReceiveOrg = UdpReceiveOrgList[0];
  31.                         UdpReceiveOrgList.RemoveAt(0);
  32.                     }

  33.                     //初步判断数据是否有效,并合并
  34.                     if (PendingDataBuffer == null)   //待处理流数据为空
  35.                     {
  36.                         PendingDataBuffer = (byte[])ReceiveOrg.DataContent.Clone();
  37.                         PendingRemote = ReceiveOrg.Remote;
  38.                     }
  39.                     else
  40.                     {
  41.                         if (PendingRemote.Address == ReceiveOrg.Remote.Address)   //判断数据来源是否相同,如果相同,连接数据
  42.                         {
  43.                             byte[] newBuffer = (byte[])PendingDataBuffer.Clone();
  44.                             PendingDataBuffer = newBuffer.Concat(ReceiveOrg.DataContent).ToArray();
  45.                             PendingRemote = ReceiveOrg.Remote;   //为防止来源地址其他属性发生变化,进行更新
  46.                         }
  47.                         else     //如果不同,丢弃原来的数据,并把丢弃的数据通过Log输出
  48.                         {
  49.                             //输出Log
  50.                             string str = "【" + ProjectSetting.ProjectCode + "】" + "NWGY接收数据出现无效数据段:" + PendingRemote.Address.ToString() + ":" + PendingRemote.Port.ToString() + ",";
  51.                             foreach (byte d in PendingDataBuffer)
  52.                             {
  53.                                 str += d.ToString("X2") + " ";
  54.                             }
  55.                             Log.WriteLine(str);

  56.                             //通信错误数+1
  57.                             lock (CommunicatorStateLocker)
  58.                             {
  59.                                 CommunicatorState.CommunicationErrorCount++;
  60.                             }

  61.                             PendingDataBuffer = (byte[])ReceiveOrg.DataContent.Clone();
  62.                             PendingRemote = ReceiveOrg.Remote;
  63.                         }
  64.                     }

  65.                     //将初步处理的数据,进行识别
  66.                     while (true)   //进行多次识别,直到不存在有效数据
  67.                     {
  68.                         if (PendingDataBuffer == null)
  69.                         {
  70.                             break;
  71.                         }

  72.                         //识别连接后的数据,输出有效数据、无效数据、未完成数据
  73.                         //有效数据存入
  74.                         DataIdentResultStruct DataIdentResult = HelperNWGY10Encoding.IdentData(PendingDataBuffer);   
  75.                         if (DataIdentResult == null)
  76.                         {
  77.                             break;
  78.                         }

  79.                         if (DataIdentResult.InvalidData != null)   //无效数据通过LOG输出
  80.                         {
  81.                             string str = "【" + ProjectSetting.ProjectCode + "】" + "NWGY数据识别出现无效数据段:" + PendingRemote.Address.ToString() + ":" + PendingRemote.Port.ToString() + ",";
  82.                             foreach (byte d in PendingDataBuffer)
  83.                             {
  84.                                 str += d.ToString("X2") + " ";
  85.                             }
  86.                             Log.WriteLine(str);

  87.                             //通信错误数+1
  88.                             lock (CommunicatorStateLocker)
  89.                             {
  90.                                 CommunicatorState.CommunicationErrorCount++;
  91.                             }
  92.                         }
  93.                         PendingDataBuffer = DataIdentResult.IncompleteData;   //未完成数据进行缓存,以便进行下一次识别
  94.                         if (DataIdentResult.ValidData != null)        //存在有效数据,进行缓存,并进行下一次识别,否则跳出识别循环
  95.                         {
  96.                             UdpReceiveDataStruct ReceiveData = new UdpReceiveDataStruct();
  97.                             ReceiveData.Remote = PendingRemote;
  98.                             ReceiveData.DataContent = (byte[])DataIdentResult.ValidData.Clone();
  99.                             lock (UdpReceiveDataListLocker)
  100.                             {
  101.                                 UdpReceiveDataList.Add(ReceiveData);
  102.                             }
  103.                         }
  104.                         else
  105.                         {
  106.                             break;
  107.                         }
  108.                     }
  109.                 }

  110.                 //这里是对识别好的数据进行处理的部分了,删去了。
  111.                 ...
  112.                 //数据处理部分结束

  113.                 if (ServiceStopFlag == true)
  114.                 {
  115.                     break;
  116.                 }

  117.                 //挂起一下,防止CPU利用率过高
  118.                 Thread.Sleep(10);

  119.             }
  120.         }
复制代码


2、处理处理代码中使用的数据识别提取函数

  1. public static DataIdentResultStruct IdentData(byte[] Data)
  2.         {
  3.             if (Data == null)
  4.             {
  5.                 return (null);
  6.             }

  7.             DataIdentResultStruct DataIdentResult = new DataIdentResultStruct();
  8.             byte[] OrgData = (byte[])Data.Clone();

  9.             //查找数据包起始码
  10.             for (int i = 0; i < OrgData.Length; i++)
  11.             {
  12.                 if (OrgData[i] == 0x68)
  13.                 {
  14.                     //找到一个起始码,计算剩下的数据长度是否可能构成一个数据包
  15.                     if (i + 12 > OrgData.Length)   //数据长度不够
  16.                     {
  17.                         if (i > 0)
  18.                         {
  19.                             DataIdentResult.InvalidData = OrgData.Take(i).ToArray();
  20.                         }
  21.                         DataIdentResult.IncompleteData = OrgData.Skip(i).ToArray();

  22.                         return DataIdentResult;
  23.                     }

  24.                     //根据协议计算剩下的数据长度是否可构成一个数据包
  25.                     int DataSegLenth = OrgData[i + 8] * 256 + OrgData[i + 9];
  26.                     int PacketLenth = 12 + DataSegLenth;
  27.                     if(i+ PacketLenth> OrgData.Length)     //数据长度不够
  28.                     {
  29.                         if (i > 0)
  30.                         {
  31.                             DataIdentResult.InvalidData = OrgData.Take(i).ToArray();
  32.                         }
  33.                         DataIdentResult.IncompleteData = OrgData.Skip(i).ToArray();

  34.                         return DataIdentResult;
  35.                     }

  36.                     //判断数据包结束码
  37.                     if (OrgData[i + PacketLenth - 1] != 0x16)   //结束码不正确,继续循环
  38.                     {
  39.                         continue;
  40.                     }

  41.                     //计算SUM是否正确
  42.                     if (SumCalc(OrgData, i + 1, PacketLenth - 3) != OrgData[i + PacketLenth - 2])   //SUM不正确,继续循环
  43.                     {
  44.                         continue;
  45.                     }

  46.                     //能运行至此,说明数据包是正确的
  47.                     if (i > 0)
  48.                     {
  49.                         DataIdentResult.InvalidData = OrgData.Take(i).ToArray();
  50.                     }
  51.                     DataIdentResult.ValidData = OrgData.Skip(i).Take(PacketLenth).ToArray();
  52.                     if (i + PacketLenth < OrgData.Length)
  53.                     {
  54.                         DataIdentResult.IncompleteData = OrgData.Skip(i + PacketLenth).ToArray();
  55.                     }

  56.                     return DataIdentResult;
  57.                 }
  58.             }

  59.             //如果循环执行到结束了,说明没找到有效的数据包,所有的数据均为未完成数据
  60.             DataIdentResult.IncompleteData = (byte[])OrgData.Clone();

  61.             return DataIdentResult;
  62.         }
复制代码

一周热门 更多>