现在已经正在使⽤此SocketAsyncEventArgs实例进⾏异
使⽤C#socket的模型 socketAyncEventArgs时遇到了不⼩的问题,
"现在已经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作"
想必很多同学都遇到此类问题了。即所谓的SocketAsyncEventArgs异步通信⽅式不能
同时执⾏ReceiveAsync⽅法,⼜执⾏SendAsync⽅法
对《深⼊探析c# Socket》的评论部分,从中可以接触⼀些知识点和技巧,值得学习。
#1楼 dreamhappy  2010-09-08 18:48
希望博主能写⼏篇关于
c# 环境 c/s多线程socket开发,如何及时的释放线程关闭线程和socket的顺序应该怎样处理的博⽂,因为我之前socket编程时候客户端和服务器端分别有⼀个线程和⼀个socket 往往线程不知道什么时候合理的释放
#2楼秋⾊
2010-09-08 19:27
线程的释放,⼀般是定义开关变量。让线程⾃⼰退出。
while(开关)
{
if(??)
{
开关=false;
}
}
#3楼 %admin
2010-09-09 10:36
实际测试了⼀下,还真出现了楼主描述的问题,我想这问题主要就出在了Buffer池的使⽤上,Send的时候发送的是从e.buff 拷贝出来的真实⼤⼩的数据,SendAsyn的时候发送的是e.buff 。楼主还真是细⼼啊,不过好像实际中要发送数据给客户端的时候不应该在⽤e.buff了,此问题有待继续深⼊
#4楼[楼主] ⽥志良
2010-09-09 10:37
@dreamhappy
多线程在Socket开发中尤为重要,若处理不当,会严重影响效率,接下来,我会陆续写些这类博⽂,谢谢⼤家关注。
#5楼[楼主] ⽥志良
2010-09-09 10:42
@安度
如果你想使你的Socket服务器⾮常⾼效,池是⼀定⽤到的,如果不⽤池,⾼级消息队列也⾏,这样才能极⼤提⾼并发数和最⼤连接数。
#6楼 %admin
2010-09-09 10:42
还好SocketAsyncEventArgs 提供了SetBuffer ,遇到这种情况是,不妨在SendAsyn之前动态的 e.SetBuffer ⼀下,就没问题了~~
⽰例:
e.AcceptSocket.Send(data);
System.Threading.Thread.Sleep(1000);
e.SetBuffer(0, data.Length);
if (!e.AcceptSocket.SendAsync(e))
{
Console.WriteLine("asynsend error");
}
#7楼[楼主] ⽥志良
2010-09-09 10:44
@九九
⽬前我开发的IM系统正在做压⼒测试,基本上最⼤连接数能上到20000,并发能上到3000。你所提的问题平时我也有遇到过,有空⼤家⼀起研究研究。
#8楼 %admin
2010-09-09 10:51
其实把下⾯3处代码关联起来看下就⽐较容易了解为什么会出现这种情况了,
if (Buffer.SetBuffer(e))
{
if (!e.AcceptSocket.ReceiveAsync(e))  //是否触发 Asyn_Commpleted事件
{
BeginReceive(e);
}
}
这段是接受连接时调⽤Buffer类的SetBuffer⽅法,实际上还是操作的SocketAsyncEventArgs.SetBuffer
internal Boolean SetBuffer(SocketAsyncEventArgs args)
{
if (this.freeIndexPool.Count > 0)
{
args.SetBuffer(this.buffer, this.freeIndexPool.Pop(), this.bufferSize);
}
else
{
if ((this.numSize - this.bufferSize) < this.currentIndex)
{
return false;
}
args.SetBuffer(this.buffer, this.currentIndex, this.bufferSize);
this.currentIndex += this.bufferSize;
}
return true;
}
看Buffer类的SetBuffer函数就很清楚了,这个Buffer池与SocketAsyncEventArgs不存在逻辑上的关联,只是外部分配缓冲区然后设置SocketAsyncEventArgs
e.AcceptSocket.Send(data);
System.Threading.Thread.Sleep(1000);
e.SetBuffer(0, data.Length);
if (!e.AcceptSocket.SendAsync(e))
{
Console.WriteLine("asynsend error");
}
到这⾥,SendAsyn 实际上使⽤的缓冲区是在Accept时候就设置好了的,所以此时如果不进⾏e.SetBuffer(0, data.Length); 就出现了,楼主描述的问题,
#9楼[楼主] ⽥志良
2010-09-09 11:10
@%admin
Buffer池主要⽤于集中管理SAEA的Buffer缓冲区,防⽌内存碎⽚过多影响效率。SetBuffer⽅法是为SAEA分配内存缓冲区,这个是跟基础系统缓冲区是有区别的。我们⽤程序可以管理SAEA内存缓冲区,但不能管理基础系统缓冲区,这个是由基础系统本⾝的机制决定的。还有微软提供的 SendAsyn⽅法是鸡肋,⼀个SAEA在同⼀时间,不能既处于SendAsync状态⼜处于ReadAsyc状态,否则会引发"现在已经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作"异常,这对于多线程、⾼并发通信毫⽆⽤处,显得很苍⽩⽆⼒。
#10楼 %admin
2010-09-09 11:29
引⽤⽥志良:
@%admin
Buffer池主要⽤于集中管理SAEA的Buffer缓冲区,防⽌内存碎⽚过多影响效率。SetBuffer⽅法是为SAEA分配内存缓冲区,这个是跟基础系统缓冲区是有区别的。我们⽤程序可以管理SAEA内存缓冲区,但不能管理基础系统缓冲区,这个是由基础系统本⾝的机制决定的。还有微软提供的 SendAsyn⽅法是鸡肋,⼀个SAEA在同⼀时间,不能既处于SendAsync状态⼜处于ReadAsyc状态,否则会引发"现在已
经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作"异常,这对于多线程、⾼并发通信毫⽆⽤处,显得很苍⽩⽆⼒。
呵呵,你说的这问题也注意到了,我还是不够深⼊,对于SAEA还没有了解,因为⾃⼰项⽬中代码跟你的很相似也就⾃⼰测试了下,分析的
也不知道对不对,呵呵,继续学习!去看看SAEA
#11楼 henry
2010-09-09 11:46
其实SocketAsyncEventArgs性能不错的,在新的测试中cpu E5405 的服务器,服务端接收256byte数据并返回给client(有分包处理)其秒处理数据包的能⼒在2.5W. ⽽CPU只占⽤了50%,内存在300M内.
补充:这样的处理⽅式在秒处理5000消息的时候估计会性能问题产⽣.
#12楼阿三
2010-09-09 14:31
⼩伙⼦进步不错嘛。
#13楼⽆为⽆知⽆欲
2010-09-09 16:27
楼主,我刚做了这个 3.5 完成端⼝⽅法的测试,⼀台普通的服务器,2G内存,可以并发接受1500条消息/秒,这个瓶颈主要是从消息队列写进数据库的瓶颈,超过后就会造成消息队列的增长,但前端还是能不断接收数据的。所以如果数据库服务器更⾼效的话,能⼒还能⼤幅提⾼。
最⾼连接我做到了20000,CPU,和内存还没怎么提⾼,所以应该能更⾼,问题是测试的时候这么多的客户端不好做啊。
#14楼[楼主] ⽥志良
2010-09-09 17:16
@⽆为⽆知⽆欲
所以你要做⼀个SQL池,将要执⾏的SQL语句放到池中,然后每隔⼀段时间,安排⼀条线程扫描SQL池,
如果SQL池中有SQL语句,则批量执⾏,如果没有则退出。在对SQL池管理时要尤为⼩⼼,Push操作和Ececute操作要互斥,执⾏SQL语句时,不能Push SQL语句,相
反,Push SQL语句时,也不能执⾏SQL语句。
#15楼安度
2010-09-09 17:28
我是最近才接触Socket的,貌似SocketAsyncEventArgs我没有在⽹上看到,⼤概⽤的都是BeginXXX和EndXXX,服务端的话,基本是⽤多线程(Accpet在⼀个独⽴的线程),然后做⼀个线程池的管理类(貌似有现成的线程池),不知道楼主这种⽅法有什么优点,不防解释下
#16楼安度
2010-09-09 17:33
在.NET 3.5⾥System.Net.Sockets空间下有⼀组增强功能的类,提供可供专⽤的⾼性能套接字应⽤程序使⽤的可选异步模
式,SocketAsyncEventArgs 类就是这⼀组增强功能的⼀部分。该类专为需要⾼性能的⽹络服务器应⽤程序⽽设计。应⽤程序可以完全使⽤增强的异步模式,也可以仅仅在⽬标热点区域(例如,在接收⼤量数据时)使⽤此模式。以下是关于此类的介绍(摘⾃MSDN)
原来是3.5⾥⾯的!是不是就是传说中的IOCP?有机会楼主写详细点,原来不知道楼主是⽤的这个!
#17楼[楼主] ⽥志良
2010-09-09 18:07
@安度
我的做法是开通300或更多个Socket⽤于接受侦听Socket传递的SAEA,为什么要开通这么多?你在做压⼒测试时就明⽩了,开通多⼀点,会使你的连接效率、连接速度⼤幅度提⾼。对于SAEA,它不能同时ReceiveAsync、SendAsync,所以采⽤双⼯通信,让收发数据在同⼀条连接上进⾏,以提⾼效率。对于业务逻辑层上的处理,主要采⽤线程池、SQL池,⽤SQL池主要将⽹络层与数据访问层分离,为什么要分离?数据库操作会极⼤影响效率,如果不分离,数据操作会拖垮⽹络层。
#18楼 Leon Weng
2010-09-11 02:07
前段时间搞视频通信时⽤到了sokect,顺便研究了⼀下,感觉效率的确⽐较⾼,但是在多线程⽅⾯⾃我感觉很差,所以没有使⽤socket完成改成WCF了,WCF封装了SOCKET,更好⽤了。
#19楼 ToBin
2011-03-01 11:12
双⼯通信时需要⼀个客户端连接两个端⼝嘛,⼀个收,⼀个发?
现在已经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作。
为什么会出现这个问题呢?
#20楼[楼主] ⽥志良
2011-03-01 11:30
@ToBin
当⼀个SAEA对象已处于StartReceive状态时,就不能⽤此SAEA发送消息。也就是说SAEA对象在⼀个时刻中只能处于 StartAccept、StartReceive、StartSend状态中的⼀种。解决的办法就是⽤双⼯通信,
为⼀条连接开辟两个SAEA对象,⼀个⽤于收,⼀个⽤于发。
#21楼 ToBin
2011-03-01 13:02
刚⼜把⽂章仔细读了⼀遍,很多东西还是没有理解!
刚好看到您的回复!很有帮助,我再研究研究您的⽂章!
还有这个saea的三种状态,我现在在发送的时候报错"
现在已经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作"
但我这个确实是clientsocket.sendasync(saeasender)是发⽣的。
我接受的时候⽤的iveasync(saeareceiver),两个没有冲突啊,很奇怪!
#22楼[楼主] ⽥志良
2011-03-01 14:55
@ToBin
建议Receive⽤异步模式,Send⽤同步模式。
#23楼 ToBin
2011-03-01 17:31
错误“现在已经正在使⽤此 SocketAsyncEventArgs 实例进⾏异步套接字操作”是不是因为异步发送了就返回了,但实际上还没有发送到,当第⼆次异步发送的时候,第⼀次还没发送完,就出了这个错误?
我猜测!
#24楼[楼主] ⽥志良
2011-03-02 16:51
ajax实例里面的函数@ToBin
当Socket处于StartSend状态时,也不能执⾏发送操作,必须等到发送回调事件触发后,才能继续执⾏StartSend。解决的办法是:记录Socket的当前状态,并存储在Socket的UserToken对象下,当要执⾏St
artSend时,判断状态。不过这样效率会很慢,当并发量达到 3000时,会报很多错,推荐的⽅法是⽤同步发送。不要觉得同步发送就⼀定会⽐异步发送慢,事实证明,对于SocketAsyncEventArgs,同步发送⽐异步发送快多了。
#25楼 ToBin
2011-03-02 17:17
拜读了,现在还有⼀个问题请教,异步的时候是“但异步发送消息的拷贝,是将Socket⾃带的Buffer空间内的所有数据,拷贝到基础系统发送缓冲区,并⽴即返回”这个基础系统缓冲区是对应winsocket的,有点疑惑,就是只有⼀个缓存区,接受也从基础系统缓冲区中拷贝处来,发送也是拷贝到这,如果我接收的时候同时发送,基础系统缓冲区⾥的数据还没取出来,将要取出来的时候发送,拷贝进去,会不是导致接收出来的数据不正确?导致脏读,数据错误!
有这样的问题嘛?
#26楼[楼主] ⽥志良
2011-03-02 18:04
@ToBin
不会导致这个问题,基础系统缓冲区为每个Socket分配发送缓冲区和接受缓冲区,这两个不冲突。
#27楼 ToBin
2011-03-02 18:33
要西,外瑞thank you !哈哈
#28楼[楼主] ⽥志良
2011-03-02 18:45
@ToBin
呵呵,不客⽓。
#29楼 ToBin
2011-03-03 17:02
呵呵,⼜碰到问题了,可能我太笨了,您在这篇⽂章“Socket服务器整体架构概述”中说到⼀个“消息队列调度器”,这个东西该怎么实现,能
⼤概说说嘛?
谢谢了!呵呵
#30楼[楼主] ⽥志良
2011-03-04 09:03
@ToBin
呵呵,把你的邮箱发给我,这个周末我写个Demo给你。
#31楼 ToBin
2011-03-04 09:26
太感谢了,激动!我的邮箱:tuablove@126
⾟苦您了!
#32楼 ToBin
2011-03-07 10:07
您的邮件已经收到,思路已经了解,⾮常感谢能得到您的帮助,希望能继续得到您的帮助,思路也⾏,呵呵,⾮常感谢!
#33楼 ToBin
2011-03-08 17:26
⼜碰到个问题,不知道怎么处理了,问题是这样的
entityData data=getdata();
public void getdata()
{
var data=null;
//...
socket.sendasync()
//...
ivesync();
return data;
}
getdata⽅法是socket 发送命令,接收返回值的⽅法,因为socket 服务器发送,接受时分开的,我怎么在getdata中让⽅法阻塞,让服务器接收到命令,然后再把结果发送过来!类似于javascript 的ajax!这种东西该怎么写啊?
类似于使⽤memcache ⾥
MemcachedClient mc = new MemcachedClient();
mc.Get("key");
这⾥⾯这个mc.Get("key") ⽅法是怎么实现的啊?
#34楼 ToBin
2011-03-09 21:02
志良哥,您好,我在socket 开发中碰到了⼀些问题,想请教您,已经发送您邮箱了,思路解说在邮件⾥,代码在附件!等待您的回复!
#35楼 edwardxh
2011-11-16 09:33
引⽤⽥志良:
@ToBin
呵呵,把你的邮箱发给我,这个周末我写个Demo给你。
楼主您好,不知您是否可以把这个“Socket服务器整体架构概述”Demo也发给我⼀份,因为我最近也在研究Socket通信,很希望能得到您的技术⼼得分享,谢谢!
我的邮箱:79668157@qq
#36楼 glf
2011-11-23 17:19
现在公司要求能够接受2W左右的服务端,每5秒访问⼀次,⾼能不能给点意见啊
怎么样,⽬前采⽤了异步接收,同步发送的⽅法,暂时解决问题。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。