我在CodeProject上google了很久,发现没人在.Net中使用过 AcceptEx 这个API
BOOL AcceptEx(
  __in          SOCKET sListenSocket,
  __in          SOCKET sAcceptSocket,
  __in          PVOID lpOutputBuffer,
  __in          DWORD dwReceiveDataLength,
  __in          DWORD dwLocalAddressLength,
  __in          DWORD dwRemoteAddressLength,
  __out         LPDWORD lpdwBytesReceived,
  __in          LPOVERLAPPED lpOverlapped
);sListenSocket是已经与IOCP关联的服务器listening Socket
sListenSocket是提前创建的与客户端通信的Socket
lpOutputBuffer是输出缓存区,用于接收地址信息等最后一个参数是重叠结构体,在.Net中对应的是 NativeOverlapped结构, 通过Overlapped.Pack方法可以得到 NativeOverlapped指针:[CLSCompliantAttribute(false)]
[ComVisibleAttribute(false)]
public NativeOverlapped* Pack(
IOCompletionCallback iocb,
Object userData
)对于参数 userData的解释是:An object or array of objects representing the input or output buffer for the operation. Each object represents a buffer, for example an array of bytes.那么调用这个函数的时候,如果是在C里面,一般会使用扩展的Overlapped结构传递到最后一个参数lpOverlapped,用于存储Per Socket Data. 而.Net中的Overlapped.Pack方法是如何传递这个数据的呢?IOCompletionCallback的原型是:[ComVisibleAttribute(true)]
[CLSCompliantAttribute(false)]
public delegate void IOCompletionCallback(
uint errorCode,
uint numBytes,
NativeOverlapped* pOVERLAP
)是不是我将Socket关联到了 IOCP后,如果有 事件边缘触发此回调就能够被自动调用?就算被调用了,我如何来获得和此Socket的关联数据?实在想不通.Net中如何调用这个API,难道是使用Marshal.AllocHGlobal来完全地复制C的方式?传递内存地址?在Native Win32中,PE文件的Optional Header规定了一个进程能够使用的最大堆空间、栈空间,保留堆空间、栈空间。
如果我使用Marshal.AllocHGlobal是不是也会受此影响?对于.Net对象,可以使用GCHandle.Alloc做到对象被Pinned,防止GC对.Net对象收集整理导致地址的改变,public static GCHandle Alloc(
Object value,
GCHandleType type
)请问这个是线程安全的么?MSDN说得好模糊~~各位高手做IOCP TCP server的时候是如何来做的?是完全复制Win32的做法?

解决方案 »

  1.   


    //好奇怪啊,我下面的代码老是抛异常,说optValue错误
    clientSocket.SetSocketOption(SocketOptionLevel.Socket
                            , SocketOptionName.UpdateAcceptContext
                            , m_Socket.Handle
                            );// 不管怎么写它都说 optValue错误
    clientSocket.SetSocketOption(SocketOptionLevel.Socket
                            , SocketOptionName.UpdateAcceptContext
                            , m_Socket
                            );// 我现在只能使用p/invoke了, 这样就可以,哪位可以给出不是p/invoke的写法??
            {
                IntPtr ptr = Marshal.AllocHGlobal(IntPtr.Size);
                Marshal.WriteIntPtr( ptr, socket.Handle);
                int ret = setsockopt(clientSocket.Handle
                    , SOL_SOCKET
                    , SO_UPDATE_ACCEPT_CONTEXT
                    , ptr
                    , IntPtr.Size
                    );
                Marshal.FreeHGlobal(ptr);
                return ret;
            }
      

  2.   

    Microsoft 已经把网络用的完成端口完整地封装在 Socket 里面,不明白咋的那么多人还去重写的,是觉得自己的写的代码比 Microsoft 的漂亮,还是高效?
      

  3.   


    可定制性不行啊, 如果是2*4核处理器,我想指定2个接受者、发送者线程工作在前面2个核上,如果我想使用自己的内存管理,这些都没有提供啊有没有人真正比对过 P/Invoke 和 Socket的 AIO的性能差异呢???
      

  4.   

    http://user.qzone.qq.com/66594958/infocenter?ptlang=2052
      

  5.   

    http://b.qzone.qq.com/cgi-bin/blognew/blog_output_data?uin=66594958&blogid=1234945044&imgdm=imgcache.qq.com&bdm=b.qzone.qq.com&mode=2&numperpage=15&blogseed=0.4411217309458841&property=GoRE&timestamp=1258702373
      

  6.   

    说实在的.net自带的socket效率在很多时候不行,可能你没有觉得,当然主要看你应用环境,如果你只是做一个普通的网络连接,或者web service之类那是够用了,如果是一个大型的在线连接,例如网游服务端,大型对局室等等,远远不够。
    P/Invoke看你怎么实现,也有相当的性能损耗,但比.net自带的好,为什么好,都一样的函数?因为.net各类检查太多,不是函数本身问题,而是为什么执行这个函数所附带的其他检查代价
      

  7.   

    假如一个大型应用不使用分布式的多台机器来处理,而是仅仅靠优化一台机器上的代码,我觉得那也是走了一个极端。毕竟花时间写自己的Socket,还不如多买几台服务器来的快。对于一个大企业的大应用来说,可扩展性和性能的平衡更加重要。你自己写一个Socket,首先就费时费钱,后面维护起来也不是省心的事情。算总账的时候并不比多买几台服务器便宜那。
      

  8.   


    内存跟 CPU 你都要干预?还不如直接用 C++ 搞掂,然后把开放接口,简单百倍。
      

  9.   


    是吗,我们做的服务端,在最普通的双核至强上面都可以挂上千把个活跃连接,而且还很顺畅。满足通常的要求应该没有问题了。至于 P/Invoke 的实现,我认为九成程序员的代码都写得比 Microsoft 烂....同时,我亦不认同的说的类型检查拖慢速度的讲法。难道自己写的代码就不需要类型检查了?还是 Microsoft 的程序员都是白痴,净是做一些无用的检查
      

  10.   

    我曾经设计的一个服务器就是用 Native C++ 和 Managed C# 混合写的,并发可以达到5W,当然,吞吐率下降得很厉害。[url=http://www.cppblog.com/wangjia184/archive/2008/05/21/50612.html]我真的很想知道有没有人真正比对过 P/Invoke 和 Socket的 AIO 的性能差异?
    并发 - 吞吐率 曲线是怎样的? 如果我上2W的并发能够保证多少吞吐率?
      

  11.   

    http://www.intel.com/cd/ids/developer/apac/zho/recent/289648.htm?page=1对于高负荷应用,肯定是要指定CPU,针对CPU优化的使用2个不同的线程池来分别来处理 网络数据包的发送接收 以及 消息的处理.
    这样可以避免繁重的业务处理导致网络数据包接收的阻塞.根据服务器CPU情况创建线程. 服务器是2*4核心. 即双CPU, 每CPU上有4个核心.
    在逻辑上就有8个处理单元.在第1个CPU上的每个核心上创建x个线程用于发送和接收.
    即: 发送接收线程池有线程数 x*4个,位于第1个CPU上.在第2个CPU上的每个核心上创建y个线程,用于业务处理
    即: 业务处理线程池有线程数 y*4个,位于第2个CPU上具体的x,y应该按照实际的系统设置.设置的原则是:
    1. 尽量小的线程上下文切换开销
    2. 尽量高的CPU利用率(注意,是利用率,不是占用率)
    一般来说,y>x
      BOOL WINAPI SetProcessAffinityMask(
      __in          HANDLE hProcess,
      __in          DWORD_PTR dwProcessAffinityMask
    );
    //  此API用于设置进程的CPU亲缘属性,第2个参数是"位或"表示. 对于2*4核系统,则设置位0xFFDWORD_PTR WINAPI SetThreadAffinityMask(
      __in          HANDLE hThread,
      __in          DWORD_PTR dwThreadAffinityMask
    );
    //  此API用于设置线程的CPU亲缘属性,第2个参数是"位或"表示. 需要注意的是,dwThreadAffinityMask必须是dwProcessAffinityMask的子集DWORD WINAPI SetThreadIdealProcessor(
      __in          HANDLE hThread,
      __in          DWORD dwIdealProcessor
    );
    //  此API用于设置线程的首选CPU,操作系统在调度线程时优先考虑首选核心, 第2个参数是以0为基数的处理器ID 
    上述3个API都可以用来设置线程的执行单元是哪个. 一般来说,线程调度是由操作系统负责.人为的控制有时候反而会降低效率.但针对高负荷的线程处理,完全可以指定独立的CPU来优化.
    比如,设定dwThreadAffinityMask=0xF,表示此线程在1-4核上执行,具体是哪个核还是由操作系统调度.这样可以将不同用途的线程分配到不同的CPU上,因为每个CPU有自己独立的L2 Cache,这样做可以避免不同类型线程在不同CPU之间切换带来的损失.上面所说的这些都只是理论,到实际的系统中,必须经过反复的性能对比试验来确定最佳方案