仅使用.net套接字作为示例,我使用:
TcpListener listener = new TcpListener(ip, port);
while(true)
{
TcpClient client = socket.AcceptTcpClient();
DoSomethingWithClient(client);
}
但另一种方式似乎是(基于http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx):
public static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
public static void DoBeginAcceptTcpClient(TcpListener listener)
{
tcpClientConnected.Reset();
listener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), listener);
tcpClientConnected.WaitOne();
}
public static void DoAcceptTcpClientCallback(IAsyncResult ar)
{
TcpListener listener = (TcpListener) ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
DoSomethingWithClient(client);
tcpClientConnected.Set();
}
恕我直言,异步风格需要3倍的代码,看起来像goto spaghetti - 它难以阅读,并迫使你分离出相关的代码。那你为什么要使用异步方式呢?大概它必须有一些优势吗?
答案 0 :(得分:5)
它的优点是不会阻塞调用者的线程,这在创建交互式应用程序时尤为重要,即使在执行工作时也应保持响应。
由于C#5有async
/await
来使这种代码更多更易于编写和阅读。
答案 1 :(得分:1)
正如其他人所提到的,异步代码使您可以使用更少的线程,从而更好地扩展(对于服务器)并保持响应(对于UI客户端)。
特别是关于TCP / IP套接字,使用异步方法还有另一个原因:您可以同时进行写入和读取。在一般情况下,这是必要的,以防止死锁;所有大型通用服务器都使用异步套接字。
VS2012中的新async
/ await
启用了一种更自然的编写异步代码的方法。但是,由于读写流是独立的,实际的异步 socket 编程仍然相当复杂。我有一个intro to async
on my blog,最后有一些很好的后续资源。
我相信你只是使用套接字作为同步或异步的例子,但如果你真的对在这个级别使用套接字感兴趣,你也可能会发现我的TCP/IP .NET Sockets FAQ很有用。
答案 2 :(得分:0)
对于大量并发客户端,使用异步与同步方法允许应用程序在执行相同工作时使用较少的线程。
E.g。我刚刚运行了一个应用程序,它首先使用大约30个线程创建/管理2000个传出连接(当线程返回到线程池时更少)。
然而,以这种方式编程通常会稍微复杂一些,并且可能有点滑,因为您必须减少所有阻塞线程的来源以最大化优势。
新的async
/ await
语法减少了代码spaghetti的问题,并允许您编写包含异步调用的常规“完整”方法。
如果您不能使用C#5和async
/ await
语法,还有其他方法,例如J. Richter的AsyncEnumerator。