使用.Net Socket 的 SocketAsyncEventArgs 方式做服务端进行侦听接受客户端连接,当并发线程数小于50,且连接的客户端(工业设备)较为稳定不会时常断线时,客户端数量达到3万以上均无问题,且CPU及内存使用量都非常小。但是发现以下情况时服务端会出现崩溃:1、 并发线程数超过 50 时,会出现服务端无法接受新的客户端连接。    经过反复实验发现,再次调用 SocketServer.AcceptAsync(args) 方法可以恢复接受连接,所以估计是 .Net Socket 内部处理问题,导致 args.Completed 事件没有产生。2、 连接到到服务端的设备大批量同时掉线时会出现以下异常,该异常无法捕获:    System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>未处理的异常</Description><AppDomain>amschannelwin.vshost.exe</AppDomain><Exception><ExceptionType>System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>未将对象引用设置到对象的实例。</Message><StackTrace>   在 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</StackTrace><ExceptionString>System.NullReferenceException: 未将对象引用设置到对象的实例。    在 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</ExceptionString></Exception></TraceRecord>3、 某些工业设备可能未严格按照 TCP 协议进行握手、数据传输、断开连接等底层通讯,导致使用 .Net Socket 编写的服务端出现更为严重的错误,该错误也无法进行异常捕获:    检测到 FatalExecutionEngineError
    Message: 运行时遇到了错误。此错误的地址为 0x793dfbf0,在线程 0x744 上。错误代码为 0xc0000005。此错误可能是 CLR 中的 bug,或者是用户代码的不安全部分或不可验证部分中的 bug。此 bug 的常见来源包括用户对 COM-interop 或 PInvoke 的封送处理错误,这些错误可能会损坏堆栈。    以上是使用 C# 语言开发 Socket 服务器遇到的问题,但是同样的工业设备连接到 C++ 开发的服务器上没有问题,希望能与 C# 开发遇到同样问题的朋友进行交流。

解决方案 »

  1.   

    觉得问题处理的难易程序,简单到复杂可能是 2 3 1
    我的问题和你的不一样,是 异步接收 和 发送时,处理时间 和 处理能力没达到要求,比如收1秒数据处理花了1.1秒 或 1.2秒,这样要主动丢数据等处理,判断很麻烦.发送为了效率用异步,不同网络带宽时延下要发送的数据量又不一样,很少能见到有处理复杂socket的例子和经验文章.
      

  2.   

    关注下...1, 不知道你的服务器模型,看着像线程池用尽了...
    2, 没碰到过
    3, 设置一下IOControl看看能解决不
      

  3.   


    你知道 一个计算机的物理和实际连接数的极限是多少吗?你达到3W的时候已经很饱和了,不知道你用了IOCP没有,建议你能使用IOCP或者扩展一台服务器
      

  4.   

    问题1 是使用C++编写的模拟软件进行测试,设置并发线程为50,在连接数达到2000 - 5000时均会出现无法接受连接的情况,而此时服务器程序的内存占用仅为50M。但是设置并发线程小于50后,可以稳定的达到3万连接,并且内存仅为60M,CPU负荷也很低,简化后的代码如下:this.SocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    this.SocketServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    this.SocketServer.SendBufferSize = 255;
    this.SocketServer.ReceiveBufferSize = 255;
    this.SocketServer.Bind(new IPEndPoint(System.Net.IPAddress.Any, 4002));
    this.SocketServer.Listen(500);
    this.Accept();private void Accept()
    {
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.Completed += new EventHandler<SocketAsyncEventArgs>(SocketAsyncEventArgs_Completed);    try
        {
            if (this.SocketServer.AcceptAsync(args) == false)
            {
                this.AcceptCallback(args);
            }
        }
        catch (Exception)
        {
            this.Accept();
        }
    }
    以上代码未使用栈来存放空闲SocketAsyncEventArgs以达到可复用的目的,发现入栈出栈更加消耗资源消耗时间问题2和问题3 均是在现场环境中出现的,使用模拟软件未出现过此异常,且现场环境中接入的客户端数量仅为2000不到,并且通讯量并不大,服务端压力也很小。怀疑还是 .Net 底层 Socket 处理的问题。
      

  5.   

    兄弟给你个注意,直接向微软的开发人员问。有答案了别忘了给大伙说说Mariya Atanasova是 System.Net 团队测试部的一名软件设计工程师。您可以通过她的博客 blogs.msdn.com/mariya 与她取得联系。
    Larry Cleeton是 System.Net 团队的一名软件设计工程师。您可以通过他的博客 blogs.msdn.com/lcleeton 与他取得联系。
    Mike Flasko是 System.Net、Winsock 和 Winsock Kernel 团队的项目经理。您可以通过他的博客 blogs.msdn.com/mflasko 与他取得联系。
    Amit Paka是 System.Net 团队的一名软件设计工程师。您可以通过他的博客 blogs.msdn.com/amitpaka 与他取得联系。
      

  6.   

    SocketAsyncEventArgs 本身是使用的iocp。.net socket在线程很多时操作本身就有问题。
    楼主应该贴一下。
    有多少设备连接,数据上报的方式,数据间的间隔,每个包的大小.既然已经用了SocketAsyncEventArgs 为什么还要建这么多的线程。