解决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. bash Shell条件测试

    3种测试命令: test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]]  注意:EXPRESSION前后必须有空白字符 bash的测试类型 数值测试: -eq: ...

  2. 个人对于epollhup的理解

    1.原因 由于最近对于异步connect函数的测试,发现提前将一个套接字加入epoll监听队列会不断爆出epollhup事件 2.示例 ........  iEpoll = epoll_create( ...

  3. Azure Event Hub 技术研究系列2-发送事件到Event Hub

    上篇博文中,我们介绍了Azure Event Hub的一些基本概念和架构: Azure Event Hub 技术研究系列1-Event Hub入门篇 本篇文章中,我们继续深入研究,了解Azure Ev ...

  4. Java 多线程详解(四)------生产者和消费者

    Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...

  5. Unity 遮罩 点击panel以外的位置,panel关闭

    public Class Panel_ATMRechage : IPanel{ private Dictionary<string,UISprite>mSprites; } protect ...

  6. 【shell脚本实例】一个恶作剧—— kill掉占用CPU较高的matlab进程

    我们实验室有台服务器,博士们在服务器上跑MATLAB,基本都是4核都是超过95%的CPU占用,想了个恶作剧的shell 定时kill掉MATLAB程序,是不是很邪恶啊,哈哈~~~  不过我只是干过一次 ...

  7. SAS PROC MCMC example in R: Logistic Regression Random-Effects Model(转)

    In this post I will run SAS example Logistic Regression Random-Effects Model in four R based solutio ...

  8. java 与操作系统进程同步问题(一)————互斥问题

    最近学校开设了操作系统原理课程,老师要求用任意语言去模拟进程的同步和互斥问题. 在尝试的写了之后,发现这个问题非常有意思,故想记录在博客中,作为自己的学习轨迹. 个人还是比较喜欢用Java语言,所以采 ...

  9. 2016.02.01日,UdoOS系统项目正式开通了

    2016.02.01日,UdoOS系统项目正式开通了,源代码即将开放 Copyright (c) 2016

  10. 修改tomcat图标

    页面上加入: 1 <link rel="shortcut icon" href="favicon.ico" type="image/x-icon ...