解决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. 由typedef和函数指针引起的危机

    由typedef和函数指针引起的危机 昨天阅读了大神强哥的代码,发现里面用到了函数指针,也用到的typedef.本来我自以为对这两个概念有一定的认识,但是突然发现这两个东西居然用到了一起!!!!(在一 ...

  2. Error:Android Source Generator: [sdk] Android SDK is not specified.

    有时候使用intellij idea 带入android 项目,运行提示Error:Android Source Generator: [sdk] Android SDK is not specifi ...

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

    http://blog.csdn.net/lmj623565791/article/details/37970961 1.Fragment的产生与介绍 Android运行在各种各样的设备中,有小屏幕的 ...

  4. 1254 Flip and Shift

    这题是目的是把黑球和白球分开连续放,事实上只要把其中一种颜色分好在一边就可以,可以绕一个球转即是第n个球可以放在n-2或者n+2上,因为这是个环,所以只需要把黑球或者白球连续放好就可以,当一共有奇数个 ...

  5. 006开源O/R映射框架内容回顾

    Hibernate是一个O/R映射框架(也称为ORM) 从ORM词来看,O---Object(对象模型):R--- Relational(关联模型),可以做对象和关联的一种映射,当然这只是部分功能,一 ...

  6. 微信第三方登录(原生)demo

    在一家ecstore二开公司有一段时间了,公司希望往自己研发产品上面走,一直在培养新人.   最近要自己去微信登录,自己就在ectore的框架基础上,写的原生微信第三方登录以此来熟悉微信第三方登录,在 ...

  7. RColorBrewer的使用

    RColorBrewer是一个R包,使用http://colorbrewer2.org/这个网站提供的颜色.我们画一个包括八个box的boxplot时,或者在x-y散点图上画六条线时,该怎样选择颜色呢 ...

  8. 默认路由、RIPv2、OSPF、EIGRP配置(全网全通)

    1:默认路由 遇到问题:给r2配置向右的单项默认路由,通过PC1去ping主机PC2,一直显示Request timed out, 解决方法:r2配置如下: r2(config)#ip route 0 ...

  9. RabbitMQ安装配置和基于EasyNetQ驱动的基础使用

    一.RabbitMQ基本概念和原理 1.AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计. 2.Ra ...

  10. GPU编程-Thread Hierarchy(3)

    1. 如果处理的数据是二维的或者三维的,应该怎么办呢? 针对的,我们可以按照二维或者三维的方式,组织线程.老规矩,先代码.后解释 // Kernel definition __global__ voi ...