【转】Socket接收字节缓冲区
原创本拉灯
2014年04月16日 10:06:55
我们接收Socket字节流数据一般都会定义一个数据包协议( 协议号,长度,内容),由于Socket接收数据是连续的,对方发两个包过来,Socket的 Recive事件有可能只触发一次或触发三次,也就是大家听到的粘包,为解决这个粘包,所以我们必要建一个字节缓冲区,将所有的接收到的字节流全放到这个缓冲区内 由这个缓冲区来分隔每个数据包的内容。
这份代码也是为论坛某个人解决串口接收数据包时而写的。不多说了上代码:
- /// <summary>
- /// 字节缓冲器
- /// </summary>
- public class ByteQueue
- {
- private List<byte> m_buffer = new List<byte>();
- public bool Find()
- {
- if (m_buffer.Count == 0)
- return false;
- int HeadIndex = m_buffer.FindIndex(o => o == 0xAA);
- if (HeadIndex == -1)
- {
- m_buffer.Clear();
- return false; //没找到AA
- }
- else if (HeadIndex != 0) //不为开头移掉之前的字节
- {
- if (HeadIndex > 1)
- m_buffer.RemoveRange(0, HeadIndex);
- }
- int length= GetLength();
- if (m_buffer.Count <length)
- {
- return false;
- }
- int TailIndex = m_buffer.FindIndex(o => o == 0x55); //查找55的位置
- if (TailIndex == -1)
- {
- //这一步为防止连发一个AA开头的包后,没发55,而又发了一个AA
- int head = m_buffer.FindLastIndex(o => o == 0xAA);
- if (head > -1)
- {
- m_buffer.RemoveRange(0, head);
- }
- return false;
- }
- else if (TailIndex + 1 != length) //计算包尾是否与包长度相等
- {
- m_buffer.RemoveRange(0, TailIndex);
- return false;
- }
- return true;
- }
- /// <summary>
- /// 命令类型
- /// </summary>
- /// <returns></returns>
- public byte Cmd()
- {
- if (m_buffer.Count >= 2)
- {
- return m_buffer[1];
- }
- return 0;
- }
- /// <summary>
- /// 序号
- /// </summary>
- /// <returns></returns>
- public byte Number()
- {
- if (m_buffer.Count >= 3)
- {
- return m_buffer[2];
- }
- return 0;
- }
- /// <summary>
- /// 包长度
- /// </summary>
- /// <returns></returns>
- public int GetLength()
- {
- int len = 5;//AA 命令类型 序号 校验和 55
- if (m_buffer.Count >= 3)
- {
- switch (m_buffer[2]) //第三字节为序号
- {
- case 0x00: //序号
- return len + 16;
- case 0x01: //序号
- return len + 10;
- case 0x02: //序号
- return len + 12;
- }
- }
- return 0;
- }
- /// <summary>
- /// 提取数据
- /// </summary>
- public void Dequeue(byte[] buffer, int offset,int size)
- {
- m_buffer.CopyTo(0,buffer,offset,size);
- m_buffer.RemoveRange(0, size);
- }
- /// <summary>
- /// 队列数据
- /// </summary>
- /// <param name="buffer"></param>
- public void Enqueue(byte[] buffer)
- {
- m_buffer.AddRange(buffer);
- }
- }
调用列子:
- private ByteQueue queue = new ByteQueue();
- private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
- {
- int len = serialPort1.BytesToRead;
- if (len > 0)
- {
- byte[] temp = new byte[len];
- serialPort1.Read(temp, 0, len);
- queue.Enqueue(temp);
- while (queue.Find()) //while可处理同时接收到多个AA ... 55 ,AA...55的包
- {
- int length = queue.GetLength();
- byte[] readBuffer = new byte[len];
- queue.Dequeue(readBuffer, 0, length);
- OnReceiveData(readBuffer); //<这里自己写一个委托吧就OK了
- }
- }
- }
上面的字节接收容器是用List来处理为方便进出字节后移除整个数据包的字节数据,当然更高效的应用byte[] 数组作成环形缓冲会好很多相对应的写法也会难一些,
【转】Socket接收字节缓冲区的更多相关文章
- 网络编程基础【day09】:socket接收大数据(五)
本节内容 1.概述 2.socket接收大数据 3.中文字符的坑 一.概述 上篇博客写到了,就是说当服务器发送至客户端的数据,大于客户端设置的数据,则就会把数据服务端发过来的数据剩余数据存在IO缓冲区 ...
- 【python】-- Socket接收大数据
Socket接收大数据 上一篇博客中的简单ssh实例,就是说当服务器发送至客户端的数据,大于客户端设置的数据,则就会把数据服务端发过来的数据剩余数据存在IO缓冲区中,这样就会造成我们想要获取数据的完整 ...
- Python网络编程——修改套接字发送和接收的缓冲区大小
很多情况下,默认的套接字缓冲区大小可能不够用.此时,可以将默认的套接字缓冲区大小改成一个更合适的值. 1. 代码 # ! /usr/bin/env python # -*- coding: utf-8 ...
- android开发 socket接收图片并保存
逻辑:接收到socket之后需要将socket发送的图片数据保存下来并通知handler更新界面 关键代码: public void readImage(Socket socket) { try { ...
- Java基础知识强化之IO流笔记28:BufferedOutputStream / BufferedInputStream(字节缓冲区流) 之BufferedOutputStream写出数据
1. BufferedOutputStream / BufferedInputStream(字节缓冲区流)的概述 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非 ...
- Java中的字节流,字符流,字节缓冲区,字符缓冲区复制文件
一:创建方式 1.建立输入(读)对象,并绑定数据源 2.建立输出(写)对象,并绑定目的地 3.将读到的内容遍历出来,然后在通过字符或者字节写入 4.资源访问过后关闭,先创建的后关闭,后创建的先关闭 ...
- Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer)
Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.映射字节缓冲区 1>.什么是虚拟内存 答:虚拟内 ...
- 设置socket接收和发送超时的一种方式
Linux环境设置Socket接收和发送超时: 须如下定义:struct timeval timeout = {3,0}; //设置发送超时setsockopt(socket,SOL_SOCKET, ...
- C# Socket发送接收字节数组和十六16进制之间转换函数
近期在使用远程网络模块的时候, 需要用的Socket发送数据,远程模块指令为16进制. 官方提供的DEMO比较繁琐.不方便新手使用. 下面的转换函数可大大方便新手使用. // 16进制字符串转字节数组 ...
随机推荐
- TeamViewer 密码有关
TeamViewer这个密码字母代表g不是q.
- FT View SE联合Studio 5000仿真
前言:一个实际的自动化项目,都是综合性的,不仅需要PLC进行逻辑.顺序.运动等控制,还需要在上位机进行监视和操作.当没有物理PLC时,上位机软件就无法连接到实际的变量数据,开发出来的界面和功能无法验 ...
- 【6】学习C++之类的实例化及访问
类就像一张图纸,如果不去实例化,制造出相应的零件,用处就不会那么大. 实例化类有两种,一个是从栈中实例化对象: class TV { public: ]; int type; void changeV ...
- hibernate之HQL,Criteria与SQL
HQL是针对封装好的对象. HQL :hibernate自己用的sql语句 -------HQL不能出现表中的任何内容 ---------不经常使用开发中 基本查询:String hql = &q ...
- centos7 nginx配置ssl证书实现https访问同时http访问
1,首先将你申请到的nginx 分类下的ssl证书上传到nginx的config下(可以新建一个目录叫ssl.) 2.修改nginx的config配置 server {listen 80;(监听80端 ...
- Web项目容器集成ActiveMQ & SpringBoot整合ActiveMQ
集成tomcat就是随项目启动而启动tomcat,最简单的方法就是监听器监听容器创建之后以Broker的方式启动ActiveMQ. 1.web项目中Broker启动的方式进行集成 在这里采用Liste ...
- day08 文件操作
1.三种字符串: (1)u'' 普通字符串 ---> u'abc' ---> 默认的文本方式,以字符作为文本的输出方式 (2)b'' 二进制字符串 ---> b'ASCII码' -- ...
- Qt+mpg123+openal播放MP3流
#ifndef PLAYSTREAM_H #define PLAYSTREAM_H #include <QObject> #include "../libMPG123/mpg12 ...
- Linux input系统数据上报流程【转】
转自:https://segmentfault.com/a/1190000017255939 作为鸡生蛋系列文章,这里主要关注Linux input系统,主要为触摸事件上报流程. 读该文章最好有对li ...
- 使用nc传输文件和目录【转】
方法1,传输文件演示(先启动接收命令) 使用nc传输文件还是比较方便的,因为不用scp和rsync那种输入密码的操作了 把A机器上的一个rpm文件发送到B机器上 需注意操作次序,receiver先侦听 ...