Extension Methods and SocketAsyncEventArgs

来源:互联网 发布:如何更换淘宝店铺客服 编辑:程序博客网 时间:2024/04/29 05:05

该文为转帖,原文链接地址:http://www.flawlesscode.com/post/2007/12/Extension-Methods-and-SocketAsyncEventArgs.aspx

The System.Net.Sockets namespace is one of the many in .NET 3.5 to have a bit of an overhall. There are enhancements to the Socket class itself and also a new class, SocketAsyncEventArgs. The enhancements are designed for use in applications which require performance and scalability during massively high volume asyncronous socket I/O.

There are several areas in writing a socket server where bottlenecks can be introduced. The most severe is caused by .NET pinning your buffers as they're passed to winsock functions which can cause your application to crash with an OutOfMemoryException even though it actually isn't, there's a great explanation of the problem in a blog post by Yun Jin which can be found here. The second common issue is the use of the APM in high volume scenarios which leads to an IAsyncResult object being allocated for every operation, obviously not the best solution and a little hard on the GC.

This is where SocketAsyncEventArgs comes in, along with a new pattern for asyncronous operations in the Socket class. The basic gist is that your code gets to declare and instantiate these objects, unlike IAsyncResult which is created for you, and as such they can be pooled and reused.

Great! What's that got to do with Extension Methods?

Well, this new pattern (the third in .NET now!) for asyncronous operation is kind of funky looking. Basically, you create your SocketAsyncEventArgs, attach a handler to it's Completed event and then pass it into one of Socket's new "xxxAsync" methods. All Fairly straight forward, the operation completes (or doesn't!) and your callback is invoked. The catch, and the aforementiond funkyness is that if the operation actually completes synchronously then "xxxAsync" returns false and your callback is not invoked!

The MSDN sample illustrates how they deal with this (surrounding code removed):

private void StartAccept(SocketAsyncEventArgs acceptEventArg)

{

    bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);

    if (!willRaiseEvent)

    {

        ProcessAccept(acceptEventArg);

    }

}

 

private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)

{

    ProcessAccept(e);

}

 

private void ProcessAccept(SocketAsyncEventArgs e)

{

    //...

}

Pretty ugly, right? Well trust me, when it's intertwined with the rest of your socket/threading code it's a mess. Enter Extension Methods!

internal delegate Boolean SocketAsyncMethod(SocketAsyncEventArgs args);

 

internal static class AsyncSocketMethodHelper

{

    public static void InvokeAsyncMethod(this Socket socket, SocketAsyncMethod method,

        EventHandler<SocketAsyncEventArgs> callback, SocketAsyncEventArgs args)

    {

        if (!method(args))

            callback(socket, args);

    }

}

Now our code to accept a new socket looks like this:

public void StartAccept(SocketAsyncEventArgs acceptEventArg)

{

    listenSocket.InvokeAsyncMethod(listenSocket.AcceptAsync,

        AcceptEventArg_Completed,

        acceptEventArg);

}

 

private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)

{

    //...

}

Well I like it anyway! My Extension Methods are in their own namespace and are marked internal, just a convenience for me while I write my socket server, can't hurt anyone else!

 
原创粉丝点击