关于scoket 异步接收的问题

gxingmin 2011-02-10 11:18:35
void StartReceiving()
{
byte[] response = new byte[1024];
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.Completed += OnReceiveCompleted;
socketEventArg.SetBuffer(response, 0, response.Length);
m_skClient.ReceiveAsync(socketEventArg);
}

void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
{
try
{
//处理接收的数据
byte []buff=e.Buffer;
.....
catch
{
}
StartReceiving();//继续异步接收下一个数据
}


上面是我客户端接收服务器端的部分代码
问题出来了,就是当我处理接收的数据(即try里的代码)如果逻辑太复杂,执行时间过长,而服务器连续发送数据间隔过短(短于我上次处理接收数据的时间),那么下一个数据就接收不到,因为最后一行代码即(
 StartReceiving();//继续异步接收下一个数据
)还没有执行,请问如何解决这个问题?
谢谢
...全文
346 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
gxingmin 2011-02-11
  • 打赏
  • 举报
回复
找到原因了,粘包导致的
谢谢各位
蜗牛的长征 2011-02-10
  • 打赏
  • 举报
回复
耗时的逻辑放到接受完再处理啊,如果必须要在这时处理就开新的线程吧,考虑用线程池
另外SocketAsyncEventArgs对象也要注意保存重复使用啊,它就是为复用和高性能设计的,参考下MSDN中的例子吧
pokka 2011-02-10
  • 打赏
  • 举报
回复
估计得用队列
bdmh 2011-02-10
  • 打赏
  • 举报
回复
将发送的数据暂时保留在队列(列表)中,然后线程做的工作是,循环队列,逐条处理其中的内容
xuzysun 2011-02-10
  • 打赏
  • 举报
回复
提取数据后,就调用StartReceiving();
最后再处理数据 。
lizhibin11 2011-02-10
  • 打赏
  • 举报
回复
放到队列中或者异步(线程)处理
byte []buff=e.Buffer就得改为copy了,否则处理过程中e.buffer可能已经变化。
gxingmin 2011-02-10
  • 打赏
  • 举报
回复
sp1234:

用的是tcp
服务器端连续发三个包,只能收到1和2,3收不到
Send("1", client.socket);
Send("2", client.socket);
Send("3", client.socket);

如果改成下面这个,就收到1,2,3了
Send("1", client.socket);
System.Threading.Thread.Sleep(10);
Send("2", client.socket);
System.Threading.Thread.Sleep(10);
Send("3", client.socket);

或者把客户端处理接收数据的那段时间较长的逻辑代码注销掉,1,2,3也能收到
  • 打赏
  • 举报
回复
我在#10所说的,并不是想说什么“沾包”概念,而是说明tcp的缓冲机制,(当发送端“很快”地联系发送了1200字节和500个字节的时候)你第一次收到了1024个字节,然后花几秒钟去处理,这时候并不妨碍底层的tcp已经在socket缓冲区中准备好了下面的676个字节等待你下一个receive操作,此时正常地程序是根本不会出现“收不到”的问题的。
  • 打赏
  • 举报
回复
你还是写一个demo程序进行测试,只需要在你的代码上边再增加十几条代码,说明一下怎么可能“下一个数据就接收不到”吧。

如果本来就应该收得到,那么就没有什么必要考虑别的。如果收不到,应该从你的demo程序上可以看出真正的问题(而跟什么“队列、线程”无关)。
lizhibin11 2011-02-10
  • 打赏
  • 举报
回复
如果是包长段则重新设置offset和buffer以符合数据段长度
修改为
如果是包长段则重新设置offset和count以符合数据段长度
lizhibin11 2011-02-10
  • 打赏
  • 举报
回复
粘包那就是另一个问题了,针对这个问题的回答不可能用一篇详尽的文章来回复,只能就事论事。
粘包的处理一般两种方式:
一种设置另一个大接收缓冲区,这个同时也充当了队列的角色,用单独的线程按照数据包约定来逐个处理完整的包。
另一种方式就是接收时,先接收包长段,再接收数据段,通过e.SetBuffer(e.Offset + e.BytesTransferred, e.Count - e.BytesTransferred)来不断接受一个完整的包,当e.Count = e.BytesTransferred时,分析接收到的是包长段还是数据段,如果是包长段则重新设置offset和buffer以符合数据段长度,如果是数据段进行线程处理即可。
枪牌 2011-02-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bdmh 的回复:]
将发送的数据暂时保留在队列(列表)中,然后线程做的工作是,循环队列,逐条处理其中的内容
[/Quote]

+1
加油馒头 2011-02-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bdmh 的回复:]
将发送的数据暂时保留在队列(列表)中,然后线程做的工作是,循环队列,逐条处理其中的内容
[/Quote]

这是个不错的方法

就是说 处理程序与接收程序分开

用两个线程
一个线程用于网络循环接收,放入到队列中

另一个用于处理队列中的数据

GameWong 2011-02-10
  • 打赏
  • 举报
回复
正在学学同步异步。
  • 打赏
  • 举报
回复
所谓“队列”,所谓“接收时间过长、发送时间过短”,都是缺乏测试基础的。

你可以试一试,假设发送时一次就Send出来1200个自己的数据,而接收时在你receive了1024个字节之后就sleep了几秒钟,下一个receive也还是可以接收到剩余的字节的。而且假设Send端是发送1200个字节,然后紧接着Send出来500个字节,那么接收端第一次接收1024个字节,然后sleep了几秒钟,然后的receive又会接收到676个字节,完全可以收全所有字节。

如果不是第二次receive时接收676个字节,那么看看你自己的程序是怎么写的吧。
ComputerInBook 2011-02-10
  • 打赏
  • 举报
回复
你应该把你的接收数据和处理数据分开,就不存在你这个问题了。接收线程只管接收数据,将接收的数据放在一个队列或列表中,用单独的处理线程处理数据。
  • 打赏
  • 举报
回复
[Quote=引用楼主 gxingmin 的回复:]
就是当我处理接收的数据(即try里的代码)如果逻辑太复杂,执行时间过长,而服务器连续发送数据间隔过短(短于我上次处理接收数据的时间),那么下一个数据就接收不到,因为最后一行代码即(
C# code
StartReceiving();//继续异步接收下一个数据

)还没有执行,请问如何解决这个问题?
[/Quote]

tcp还是udp?tcp应该没有这个问题。如果有,还是看看你自己的程序有什么问题。
小D2013 2011-02-10
  • 打赏
  • 举报
回复
楼主,你需要用队列存储接受到的消息,然后有专门的线程处理这个队列,那个线程其实就是一个死循环的处理方法

110,499

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧