原创本拉灯

2014年04月16日 10:06:55

  • 4448

我们接收Socket字节流数据一般都会定义一个数据包协议( 协议号,长度,内容),由于Socket接收数据是连续的,对方发两个包过来,Socket的 Recive事件有可能只触发一次或触发三次,也就是大家听到的粘包,为解决这个粘包,所以我们必要建一个字节缓冲区,将所有的接收到的字节流全放到这个缓冲区内 由这个缓冲区来分隔每个数据包的内容。

这份代码也是为论坛某个人解决串口接收数据包时而写的。不多说了上代码:

  1. /// <summary>
  2. /// 字节缓冲器
  3. /// </summary>
  4. public class ByteQueue
  5. {
  6. private List<byte> m_buffer = new List<byte>();
  7. public bool Find()
  8. {
  9. if (m_buffer.Count == 0)
  10. return false;
  11. int HeadIndex = m_buffer.FindIndex(o => o == 0xAA);
  12. if (HeadIndex == -1)
  13. {
  14. m_buffer.Clear();
  15. return false; //没找到AA
  16. }
  17. else if (HeadIndex != 0) //不为开头移掉之前的字节
  18. {
  19. if (HeadIndex > 1)
  20. m_buffer.RemoveRange(0, HeadIndex);
  21. }
  22. int length= GetLength();
  23. if (m_buffer.Count <length)
  24. {
  25. return false;
  26. }
  27. int TailIndex = m_buffer.FindIndex(o => o == 0x55); //查找55的位置
  28. if (TailIndex == -1)
  29. {
  30. //这一步为防止连发一个AA开头的包后,没发55,而又发了一个AA
  31. int head = m_buffer.FindLastIndex(o => o == 0xAA);
  32. if (head > -1)
  33. {
  34. m_buffer.RemoveRange(0, head);
  35. }
  36. return false;
  37. }
  38. else if (TailIndex + 1 != length) //计算包尾是否与包长度相等
  39. {
  40. m_buffer.RemoveRange(0, TailIndex);
  41. return false;
  42. }
  43. return true;
  44. }
  45. /// <summary>
  46. /// 命令类型
  47. /// </summary>
  48. /// <returns></returns>
  49. public byte Cmd()
  50. {
  51. if (m_buffer.Count >= 2)
  52. {
  53. return m_buffer[1];
  54. }
  55. return 0;
  56. }
  57. /// <summary>
  58. /// 序号
  59. /// </summary>
  60. /// <returns></returns>
  61. public byte Number()
  62. {
  63. if (m_buffer.Count >= 3)
  64. {
  65. return m_buffer[2];
  66. }
  67. return 0;
  68. }
  69. /// <summary>
  70. /// 包长度
  71. /// </summary>
  72. /// <returns></returns>
  73. public int GetLength()
  74. {
  75. int len = 5;//AA 命令类型 序号 校验和 55
  76. if (m_buffer.Count >= 3)
  77. {
  78. switch (m_buffer[2]) //第三字节为序号
  79. {
  80. case 0x00: //序号
  81. return len + 16;
  82. case 0x01: //序号
  83. return len + 10;
  84. case 0x02: //序号
  85. return len + 12;
  86. }
  87. }
  88. return 0;
  89. }
  90. /// <summary>
  91. /// 提取数据
  92. /// </summary>
  93. public void Dequeue(byte[] buffer, int offset,int size)
  94. {
  95. m_buffer.CopyTo(0,buffer,offset,size);
  96. m_buffer.RemoveRange(0, size);
  97. }
  98. /// <summary>
  99. /// 队列数据
  100. /// </summary>
  101. /// <param name="buffer"></param>
  102. public void Enqueue(byte[] buffer)
  103. {
  104. m_buffer.AddRange(buffer);
  105. }
  106. }

调用列子:

  1. private ByteQueue queue = new ByteQueue();
  2. private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
  3. {
  4. int len = serialPort1.BytesToRead;
  5. if (len > 0)
  6. {
  7. byte[] temp = new byte[len];
  8. serialPort1.Read(temp, 0, len);
  9. queue.Enqueue(temp);
  10. while (queue.Find()) //while可处理同时接收到多个AA ... 55 ,AA...55的包
  11. {
  12. int length = queue.GetLength();
  13. byte[] readBuffer = new byte[len];
  14. queue.Dequeue(readBuffer, 0, length);
  15. OnReceiveData(readBuffer); //<这里自己写一个委托吧就OK了
  16. }
  17. }
  18. }

上面的字节接收容器是用List来处理为方便进出字节后移除整个数据包的字节数据,当然更高效的应用byte[] 数组作成环形缓冲会好很多相对应的写法也会难一些,

【转】Socket接收字节缓冲区的更多相关文章

  1. 网络编程基础【day09】:socket接收大数据(五)

    本节内容 1.概述 2.socket接收大数据 3.中文字符的坑 一.概述 上篇博客写到了,就是说当服务器发送至客户端的数据,大于客户端设置的数据,则就会把数据服务端发过来的数据剩余数据存在IO缓冲区 ...

  2. 【python】-- Socket接收大数据

    Socket接收大数据 上一篇博客中的简单ssh实例,就是说当服务器发送至客户端的数据,大于客户端设置的数据,则就会把数据服务端发过来的数据剩余数据存在IO缓冲区中,这样就会造成我们想要获取数据的完整 ...

  3. Python网络编程——修改套接字发送和接收的缓冲区大小

    很多情况下,默认的套接字缓冲区大小可能不够用.此时,可以将默认的套接字缓冲区大小改成一个更合适的值. 1. 代码 # ! /usr/bin/env python # -*- coding: utf-8 ...

  4. android开发 socket接收图片并保存

    逻辑:接收到socket之后需要将socket发送的图片数据保存下来并通知handler更新界面 关键代码: public void readImage(Socket socket) { try { ...

  5. Java基础知识强化之IO流笔记28:BufferedOutputStream / BufferedInputStream(字节缓冲区流) 之BufferedOutputStream写出数据

    1. BufferedOutputStream / BufferedInputStream(字节缓冲区流)的概述 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非 ...

  6. Java中的字节流,字符流,字节缓冲区,字符缓冲区复制文件

     一:创建方式 1.建立输入(读)对象,并绑定数据源 2.建立输出(写)对象,并绑定目的地 3.将读到的内容遍历出来,然后在通过字符或者字节写入 4.资源访问过后关闭,先创建的后关闭,后创建的先关闭 ...

  7. Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer)

    Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.映射字节缓冲区 1>.什么是虚拟内存 答:虚拟内 ...

  8. 设置socket接收和发送超时的一种方式

    Linux环境设置Socket接收和发送超时: 须如下定义:struct timeval timeout = {3,0};  //设置发送超时setsockopt(socket,SOL_SOCKET, ...

  9. C# Socket发送接收字节数组和十六16进制之间转换函数

    近期在使用远程网络模块的时候, 需要用的Socket发送数据,远程模块指令为16进制. 官方提供的DEMO比较繁琐.不方便新手使用. 下面的转换函数可大大方便新手使用. // 16进制字符串转字节数组 ...

随机推荐

  1. jq选择器(jq 与 js 互相转换),jq操作css样式 / 文本内容, jq操作类名,jq操作全局属性,jq获取盒子信息,jq获取位置信息

    jq选择器(jq 与 js 互相转换) // 获取所有的页面元素jq对象 $('css3选择器语法'); var $box = $(".box:nth-child(1)"); 获取 ...

  2. html的分类与特点

    ##块级元素##|元素|描述||--|--||h1-h6|标题||div|区分大模块||p|段落||ul>li|无序列表||ol>li|有序列表||dl>dt dd|自定义列表||t ...

  3. json 格式化的时候,日期格式化

    public class CustomIsoDateTimeConverter : IsoDateTimeConverter { public CustomIsoDateTimeConverter() ...

  4. Asp.net Core导出Excel

    本篇文章是在MVC设计模式下,基于windows系统的Excel导出 1.前台的实现不用我多说了吧,加一个a标签链接地址跳到它所调用的方法里面,可以根据当前页面的查询条件去传值,从而查询出你想要的数据 ...

  5. vue项目打包笔记

    我的需求是在同一个代码目录下,可以同时放入两个项目包,通过运行不同的命令,运行相应的项目页面以及打包相应的项目. 这样的话,代码管理比较方便,用于多个项目在同一时间开发,类型一样,但在功能上有所区分的 ...

  6. vue较深入的知识点

    1 理解何为虚拟节点 虚拟dom是什么? 虚拟dom就是通过js对象来模拟描述dom树,包括tag,attr, children等属性来代表标签名,属性,子元素等.由于不需要有操作dom的方法,所以比 ...

  7. 阿里云服务器ftp连接后21端口无法使用的问题

    今天在阿里云Centos上搭了一个ftp 服务,开启了20和21端口的权限.但是用工具和ftp命令登录,均超时. ftp命令登录成功后不能使用ls 命令,直接超时. 工具登录成功后 获取根目录失败,也 ...

  8. 搜索表字段包含某字符串的SQL和监控Oracle数据库的SQL。

    1.第一个SQL 背景:需要找到SQL Server数据库中,包含某个字符串的表,输出表和包含该字符串的列. )='=' --这里填要搜索的字符串 DECLARE @sql NVARCHAR(MAX) ...

  9. 7zip,命令行解压报错:7-Zip cannot find the code that works with archives.

    简单的命令: 7z x zipfile.7z 7-Zip 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18 Error: 7-Zip cannot ...

  10. Unity AssetBundle的生成、加载和热更新

    当前使用的是unity2018.2.6版本. 生成AssetBundle 这个版本生成AssetBundle有两种方式,一种是在资源的Inspector面板下边配置AssetBundle名称,然后调用 ...