在AsynServer中对接收函数增加接收判断,如果收到客户端发送的请求信息,则发送10个测试包给发送端,否则继续接收,修改后的接收代码如下:

        private void AsynReceive()
{
byte[] data = new byte[];//接收缓存
string receiveStr;
string[] sendArr = PackageBuilder.BuildPackage();//生成发送数组,10个包
socket.BeginReceive(data, , data.Length, SocketFlags.None, asyncResult => {
int length = socket.EndReceive(asyncResult); receiveStr = Encoding.ASCII.GetString(data, , length);//获取缓存中的信息
// Console.WriteLine(receiveStr); if (receiveStr == "") //标志字符'1',如果收到1,则发送测试包给客户端,如果不是1,继续接受
{
for (int i = ; i < ; i++)
{
Console.WriteLine("第{0}次发送:",i);
AsynSend(sendArr[i]);
// Thread.Sleep(200);
} }
else
AsynReceive();
}, null); }

View Cosde

其中if (receiveStr == "1")是接收判断,如果收到客户端发来的1,则发送测试包给客户端,如果不是1,继续接收。因为是异步发送,所以Console.WriteLine("第{0}次发送:",i);显示可能和发送数据不同步,但肯定是发送了10次。

测试一下,发送10次,接收端收到结果如下:

发了10次,而只收了8次,从上图中我们可以发现第6次和第7次发生了粘包,两个包被当作1个包接收了,如果你编写解包程序时不考虑粘包,那么解包循环在第7次解包时会抛异常。当然一种快捷的避免粘包方式是在发送函数的 AsynSend(sendArr[i]);下面加上Thread.Sleep(200);减少发送频率,但这不是长久之计,接下来我们进入客户端来处理粘包问题。

客户端主要是修改了SyncReceive方法,使用StringBuilder来做接收,因为StringBuilder较于string而言,增加字符串,删除字符串的效率比较高,代码如下:

 string[] receiveArr = new string[];//用于存储接收到的数据
int arri=;//数组位序
public virtual void SyncReceive()
{
//StringBuilder sb = new StringBuilder(1024*1024);
StringBuilder receiveSb = new StringBuilder(); //接收字符串buffer
string receiveStr; //解包过程中用于 中间处理
int index; //位序,用于解包
int dataLength; //存储接收包中的数据长度
int i = ;
Thread th = new Thread(() =>
{
while (receiveFlag)
{
byte[] buffer = new byte[];
int r = socket.Receive(buffer);
string str = Encoding.ASCII.GetString(buffer, , r); //只是用来显示
Console.WriteLine("第{0}次收到数据:{1}",i++,str);
Console.WriteLine(); receiveSb.Append(str); //存储接收字符串,可能存多个包
receiveStr = receiveSb.ToString();
index = receiveStr.IndexOf("data:");//可能有多个"data" while (index > )
{
dataLength = int.Parse(receiveStr.Substring(index - , ));//数据长度规定为2个字节
receiveArr[arri] = receiveStr.Substring(index, dataLength);//保存数据到数组中
Console.WriteLine("保存的数据数组[{0}]:{1}",arri,receiveArr[arri++]);
receiveSb.Remove(, + dataLength);//包头+数据长度字节共10个字节"HEAD|H1|38",后面是数据"data:xxxxxxxxxxxxxxxxxxxx"
receiveStr = receiveSb.ToString();
index = receiveStr.IndexOf("data:");//寻找下一个"data",如果没有跳出循环
} //sb.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, r));
}
});
th.Start(); }

方法上面加了两个全局变量,receiveArr是一个数组,用于保存接收到的实时数据,这些数据可以用于前台展示,也可以直接保存到数据库;arri是数组位序,运行结果如下:

如图所示,客户端接收了7次数据,第一次有4个包粘在了一起,但我们通过合适的解包,依然将10次数据分开保存在字符串数组中。

客户端要先发送"1"标志给客户端才能执行上面的程序,     SynSend("1");

程序的源码下载地址:

链接:http://pan.baidu.com/s/1nvfa8lF 密码:zjoa

粘包的处理是比较简单的,更麻烦的是分包,虽然不常见,但也要考虑,后面考虑做一下分包的处理,程序写的比较毛糙,如有不足之处希望大家指出。

Socket解决粘包问题2的更多相关文章

  1. c# socket 解决粘包,半包

    处理原理: 半包:即一条消息底层分几次发送,先有个头包读取整条消息的长度,当不满足长度时,将消息临时缓存起来,直到满足长度再解码 粘包:两条完整/不完整消息粘在一起,一般是解码完上一条消息,然后再判断 ...

  2. Socket解决粘包问题1

    粘包是指发送端发送的包速度过快,到接收端那边多包并成一个包的现象,比如发送端连续10次发送1个字符'a',因为发送的速度很快,接收端可能一次就收到了10个字符'aaaaaaaaaa',这就是接收端的粘 ...

  3. 网络编程基础【day09】:socket解决粘包问题之MD5(八)

    本节内容 1.概述 2.代码实现 一.概述 上一篇博客讲到的用MD5来校验还是用的之前解决粘包的方法,就是客户端发送一个请求,等待服务端的确认的这样的一个笨方法.下面我们用另外一种方法:就是客户端已经 ...

  4. Python开发【socket篇】解决粘包

    客户端 import os import json import struct import socket sk = socket.socket() sk.connect(('127.0.0.1',8 ...

  5. 【python】-- Socket粘包问题 ,解决粘包的几种方法、socket文件下载,md5值检验

    上一篇随笔:“socket 接收大数据”,在win系统上能够运行,并且解决了大数据量的数据传输出现的问题,但是运行在linux系统上就会出现如下图所示的情况: 就是服务端两次发送给客户端的数据(第一次 ...

  6. day31——recv工作原理、高大上版解决粘包方式、基于UDP协议的socket通信

    day31 recv工作原理 源码解释: Receive up to buffersize bytes from the socket. 接收来自socket缓冲区的字节数据, For the opt ...

  7. 一个完整的socket recv()案例,包括解决粘包、服务器主动推数据的问题

    前言: 本文是针对socket长连接(涉及到服务器主动推数据),每个包头的拼接算法和长度都不一样,具体的包头小伙伴们问自己公司的开发吧,本文只是提供思路.再啰嗦一句:recv到的包头中数字进行某种运算 ...

  8. python之socket编程------粘包

    一.粘包 什么是粘包 只有TCP只有粘包现象,UDP永远不会粘包 所谓粘包问题主要还是因为接收方不知道之间的界限,不知道一次性提取多少字节的数据所造成的 两种情况发生粘包: 1.发送端需要等缓冲区满才 ...

  9. python3全栈开发-什么是粘包、粘包现象、如何解决粘包

    一.粘包现象 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意注意: res=subprocess.Popen(cmd.decode( ...

随机推荐

  1. Context 之我见

    Context这个单词在程序开发中屡见不鲜,我记得以前在博客中写过一些关于这个词语的自我解释,但是我这个人有一个毛病就是健忘,如果不将自己的想法写下,不出十分钟,就被我抛到九霄云外. 真我现在还有点想 ...

  2. centos中忘记root密码问题

    centos中root密码问题   几次在虚拟机中安装cenos,都没有提示输入root密码,具体操作如下: 1.在启动的时候,进入启动界面后,按除了Enter键之外的任意键,即可进入该界面.然后 按 ...

  3. hadoop namenode启动过程详细剖析及瓶颈分析

    NameNode中几个关键的数据结构 FSImage Namenode 会将HDFS的文件和目录元数据存储在一个叫fsimage的二进制文件中,每次保存fsimage之后到下次保存之间的所有hdfs操 ...

  4. Mater Nginx(2) - A Configuration Guide

    The basic configuration format Nginx global configuration parameters Using include files The HTTP se ...

  5. apache配置虚拟主机的三种方式

    Apache 配置虚拟主机三种方式   一.基于IP 1. 假设服务器有个IP地址为192.168.1.10,使用ifconfig在同一个网络接口eth0上绑定3个IP: [root@localhos ...

  6. Loadrunner 录制成功,但是脚本并没有产生

    LR 在用IE 录制脚本已经成功,但是结束录制以后,并没有脚本产生,在产生脚本log 中提示: [Net An. Error    (14c8:1cec)] Request Connection: R ...

  7. Apriori算法实例----Weka,R, Using Weka in my javacode

    学习数据挖掘工具中,下面使用4种工具来对同一个数据集进行研究. 数据描述:下面这些数据是15个同学选修课程情况,在课程大纲中共有10门课程供学生选择,下面给出具体的选课情况,以ARFF数据文件保存,名 ...

  8. 使用 Windows PowerShell 管理Windows Azure映像

    你可以使用 Azure PowerShell 模块中的 cmdlet 管理可供你的 Azure 订阅使用的映像.这包括 Azure 提供的映像以及你上载的映像.对于某些映像任务,你还可以使用 Azur ...

  9. Linux内存寻址之分页机制

    在上一篇文章Linux内存寻址之分段机制中,我们了解逻辑地址通过分段机制转换为线性地址的过程.下面,我们就来看看更加重要和复杂的分页机制. 分页机制在段机制之后进行,以完成线性—物理地址的转换过程.段 ...

  10. 有关gcc的扩展__attribute__((unused))

    ================================ Author: taoyuetao Email: tao_yuetao@yahoo.com.cn Blog: taoyuetao.cu ...