首页 技术 正文
技术 2022年11月16日
0 收藏 350 点赞 4,784 浏览 2378 个字

在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次,接收端收到结果如下:

Socket解决粘包问题2

发了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是数组位序,运行结果如下:

Socket解决粘包问题2

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

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

程序的源码下载地址:

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

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,031
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,520
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,368
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,148
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,781
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,860