解决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#代码的更多相关文章

  1. C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

    介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...

  2. 解决socket粘包的两种low版模式 os.popen()和struct模块

    os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...

  3. 网络编程基础【day09】:解决socket粘包之大数据(七)

    本节内容 概述 linux下运行效果 sleep解决粘包 服务端插入交互解决粘包问题 一.概述 刚刚我们在window的操作系统上,很完美的解决了,大数据量的数据传输出现的问题,但是在Linux环境下 ...

  4. Python socket粘包解决

    socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...

  5. socket粘包现象加解决办法

    socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...

  6. Netty使用LineBasedFrameDecoder解决TCP粘包/拆包

    TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...

  7. 百万年薪python之路 -- socket粘包问题解决

    socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...

  8. Socket粘包问题的3种解决方案,最后一种最完美!

    在 Java 语言中,传统的 Socket 编程分为两种实现方式,这两种实现方式也对应着两种不同的传输层协议:TCP 协议和 UDP 协议,但作为互联网中最常用的传输层协议 TCP,在使用时却会导致粘 ...

  9. Socket粘包问题终极解决方案—Netty版(2W字)!

    上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...

随机推荐

  1. redis安装学习

    Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理.它支持字符串.哈希表.列表.集合.有序集合,位图,hyperloglogs等数据类型.内置复制.Lu ...

  2. 【2017-05-19】WebForm复合控件

    自动提交的属性: AutoPostBack="True" 1.RadioButtonList     单选集合 -属性:RepeatDirection:Vertical (垂直排布 ...

  3. 《Android进阶》之第六篇 Fragment 的使用2

    最近通过学习,对fragment的使用有了新的认识. 一开始接触android的时候,很是受不了这个fragment,总感觉它把一个简单的事情搞复杂啦,所以每次新建工程的时候总是固执的选择empty ...

  4. MindNode for mac 思维导图

    绘制思维导图 下载地址 链接: https://pan.baidu.com/s/1o7NBzmU 密码: mu3f

  5. vmvare虚拟机经验

    关于网络连接:如果宿主机网络类型:如果是无线网络网络适配器选择桥接模式:如果是物理网线选择NAT模式: 关于刚装完系统apt-get update出现could not lock /var/lib/l ...

  6. Java ClassLoader 原理分析

    一.ClassLoader(类加载器)的作用 如果一个程序包含不止一个class文件,那么当程序启动时,带有main方法的类的class文件作为程序入口先被JVM加载,然后根据程序调用的需要,再逐步进 ...

  7. Random Forest Classification of Mushrooms

    There is a plethora of classification algorithms available to people who have a bit of coding experi ...

  8. mongodb 创建LBS位置索引

    <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver< ...

  9. 【T-SQL进阶】02.理解SQL查询的底层原理

    本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...

  10. 数据库MySQL安装和校验

    1.安装MySQL 双击已经下载的安装包: Typical:典型安装,第一次安装建议选择该类安装 Custom:自定义安装,在对数据库熟悉后,知道自己需要哪些组件时,可以选择该类安装(这里选择的是自定 ...