解决Socket粘包问题——C#代码
解决Socket粘包问题——C#代码
前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加个线程锁搞定。后来回到家慢慢思考感觉这个和加锁没啥关系,如果是多线程导致的,消息只会被覆盖呀。后来就上网搜索socket 消息重叠,后来了解到这属于socket粘包。
简单以自己的理解介绍下Socket粘包。
Socket粘包简单说就是:Socket发送方 发送消息很频繁导致接收方接收到的消息是之前的两个或者多个消息连在一起。至于详细介绍可以百度相关资料了解。
Socket粘包一般分为两种:
1、Socket发送方:Socket发送消息时会将消息存放在一个缓冲区里,等待缓冲区满或者等待时间已到则发送出去。
2、Socket接收方:接收方一般是因为没有及时从Socket缓冲区里取数据导致后来数据累加到一起才获取导致。
在此只介绍发送方导致的
发送方处理方法一般是两种
1、NoDelay=true,NoDelay是否正在使用 Nagle 算法,这是socket提供的一个方法,我试了单独使用感觉效果不大,还有就是在发送后加延时,这样就不会造成粘包。
2、分包方法 即发送消息的头4个字节加上消息长度,接受方接收到数据后先解析长度然后根据消息长度来获取消息。每次接收数据有个总长度 在总长度里循环遍历消息即可。
直接上代码。
分包方法发送端主要代码
//测试要发送的消息
string[] sendData = new string[] { "", "", "", "", "", "我爱中国 中国爱我 哈哈哈 中国", "大中华你china"};
int userKey = listConnect.SelectedIndex;
if (userKey < )
{
MessageBox.Show("请选择要发送者!");
} else
{
//为了测试循环发送消息
for (int i = ; i < ; i++)
{ //获取消息内容
byte[] msg = Encoding.UTF8.GetBytes(sendData[i]); byte[] array = new byte[msg.Length + + ]; //第一个字节代表 消息类型 1:文字消息 2:文件
array[] = ;
//将消息长度写入4个字节 从第二个2个字节开始写入
ConvertIntToByteArray(msg.Length, ref array); //字节拷贝
Buffer.BlockCopy(msg, , array, , msg.Length);
//socket发送 dic存储的当前连接的socket列表
dic[userKey].Send(array); }
}
接收端消息部分代码
//循环监听接收消息
while (flag)
{
byte[] bytes = new byte[ * * ]; //消息总长度
int dataLength = ;
dataLength = ServerSocket.receive(out bytes); //判断消息类型
if (bytes[] == )
{ //解决粘包问题代码 int msgBeginIndex = -;
int msgEndIndex = -;
int msgLength = ;
int n = ; /**以下是接收数据包在byte[]中的内容
*
0=1 代表消息类型
1=2 消息长度(消息长度占4个字节)
2=0 ..
3=0 ..
4=0 ..
5=48 消息内容
6=48 ..
以下内容和前面结构一样,粘包导致两个消息粘在一起
7=1
8=2
9=0
10=0
11=0
12=49
13=49
...
******/
while (n < dataLength)
{
//将消息长度4个字节单独提取
byte[] msgLengthByte = new byte[]; for (int i = ; i < ; i++)
{
//msgEndIndex:消息结束所在索引
//第一个次消息长度可能是2;
//第二个长度可能是8了索引这里要使用msgEndIndex;
//最后+2+i:每个消息记录的长度都是从本次消息的第二个字节开始 直到第四个字节 //之所以msgEndIndex默认=-1 消息长度所在位置在前一个消息结束后的第二个字节开始 ;
//-1+2=1 这样保证获取第一个消息所在长度,也能保证后面的消息长度所在位置
msgLengthByte[i] = bytes[msgEndIndex + + i];
}
//将消息长度转成int
msgLength = BitConverter.ToInt32(msgLengthByte, ); //消息开始索引=消息结束索引+6(前面5个字节不是消息内容消息内容都是从第6个字节开始;+6是因为msgEndIndex索引是从-1开始)
msgBeginIndex = msgEndIndex + ; //消息结束索引位置=游标索引开始位置 +消息长度-1 因为消息开始索引本身就是消息开始 索引消息结束必须减除开始索引
msgEndIndex = msgBeginIndex + msgLength - ; //获取消息内容
string receive = Encoding.UTF8.GetString(bytes, msgBeginIndex, msgLength);
if (receive != null)
{
txtLog.BeginInvoke(new Action(() =>
{ txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss") + " " + receive + " \r\n");
}));
} n = msgEndIndex + ;
}
} //文件接收
else if (bytes[] == )
{
}
}
解决Socket粘包问题——C#代码的更多相关文章
- C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)
介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...
- 解决socket粘包的两种low版模式 os.popen()和struct模块
os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...
- 网络编程基础【day09】:解决socket粘包之大数据(七)
本节内容 概述 linux下运行效果 sleep解决粘包 服务端插入交互解决粘包问题 一.概述 刚刚我们在window的操作系统上,很完美的解决了,大数据量的数据传输出现的问题,但是在Linux环境下 ...
- Python socket粘包解决
socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...
- socket粘包现象加解决办法
socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...
- Netty使用LineBasedFrameDecoder解决TCP粘包/拆包
TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...
- 百万年薪python之路 -- socket粘包问题解决
socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...
- Socket粘包问题的3种解决方案,最后一种最完美!
在 Java 语言中,传统的 Socket 编程分为两种实现方式,这两种实现方式也对应着两种不同的传输层协议:TCP 协议和 UDP 协议,但作为互联网中最常用的传输层协议 TCP,在使用时却会导致粘 ...
- Socket粘包问题终极解决方案—Netty版(2W字)!
上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...
随机推荐
- 浅谈mmap()和ioremap()的用法与区别
一.mmap()mmap()函数是用来将设备内存线性地址映射到用户地址空间.(1)首先映射基地址,再通过偏移地址寻址:(2)unsigned char *map_cru_base=(unsigned ...
- (转载)sizeof
[C++专题]C++ sizeof 使用规则及陷阱分析 摘要:鉴于sizeof为各大软件公司笔试.面试必考题,现收集sizeof的各种用法,尽量做到全面理解,其中例子希望能举一反三.提示:下文例子 ...
- 连续分段累计器FPGA实现的探讨
- 软件需求规格说明书(spec)
1.spec 的目标是什么,spec 的目标不包括什么? 我们的目标是对用户发布的各种需求(需要伙伴的需求)进行处理,使别的用户可以看到信息,并且成功找到合适的伙伴一起! 不包括对用户之间的联系. 2 ...
- Best packages for data manipulation in R
dplyr and data.table are amazing packages that make data manipulation in R fun. Both packages have t ...
- 在容器中利用Nginx-proxy实现多域名的自动反向代理、免费SSL证书
在个人的小项目或者测试环境中,配置反向代理显得十分繁琐,而借助 Nginx-proxy 的镜像,即使是小白,也能快速实现域名转发. 1.域名.IP自动转发 在开始之前,首先黑进了自家的路由器,将某个域 ...
- nodeJS之路径PATH模块
前面的话 path模块包含一系列处理和转换文件路径的工具集,通过 require('path') 可用来访问这个模块.本文将详细介绍path模块 路径组成 [path.dirname(p)] 返回路径 ...
- golang实现dns域名解析(三):响应报文分析
前面说了构造请求发送报文,接下来我们好好研究下如何解析服务器端发回来的应答信息. 首先还是用前面的程序代码发一个请求,用抓包工具看看应答的内容有哪些: 截图的第一部分是返回信息的统计,表明这个返回的包 ...
- PHP实现Collection数据集类及其原理
本文目录 : Collection源码 讲解与例子 ArrayAccess的使用 JsonSerializable的使用 Countable的使用 IteratorAggregate.ArrayIte ...
- (原创)Maven+Spring+CXF+Tomcat7 简单例子实现webservice
这个例子需要建三个Maven项目,其中一个为父项目,另外两个为子项目 首先,建立父项目testParent,选择quickstart: 输入项目名称和模块名称,然后创建: 然后建立子项目testInt ...