我以前使用过BeginAccept()
和BeginRead()
,但与Visual Studio 2012我想利用新的异步的(async
,await
)功能在我的socket服务器程序.
我该如何完成AcceptAsync
和ReceiveAsync
功能?
using System.Net; using System.Net.Sockets; namespace OfficialServer.Core.Server { public abstract class CoreServer { private const int ListenLength = 500; private const int ReceiveTimeOut = 30000; private const int SendTimeOut = 30000; private readonly Socket _socket; protected CoreServer(int port, string ip = "0.0.0.0") { _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port)); _socket.Listen(ListenLength); _socket.ReceiveTimeout = ReceiveTimeOut; _socket.SendTimeout = SendTimeOut; _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); } public void Start() { } } }
spender.. 56
...因为你如此坚定,我汇总了一个非常简单的例子,说明如何编写一个echo服务器来帮助你.收到的任何内容都会回复给客户端.服务器将保持运行60秒.尝试在localhost端口6666上telnet到它.花点时间了解这里发生了什么.
void Main() { CancellationTokenSource cts = new CancellationTokenSource(); TcpListener listener = new TcpListener(IPAddress.Any, 6666); try { listener.Start(); //just fire and forget. We break from the "forgotten" async loops //in AcceptClientsAsync using a CancellationToken from `cts` AcceptClientsAsync(listener, cts.Token); Thread.Sleep(60000); //block here to hold open the server } finally { cts.Cancel(); listener.Stop(); } } async Task AcceptClientsAsync(TcpListener listener, CancellationToken ct) { var clientCounter = 0; while (!ct.IsCancellationRequested) { TcpClient client = await listener.AcceptTcpClientAsync() .ConfigureAwait(false); clientCounter++; //once again, just fire and forget, and use the CancellationToken //to signal to the "forgotten" async invocation. EchoAsync(client, clientCounter, ct); } } async Task EchoAsync(TcpClient client, int clientIndex, CancellationToken ct) { Console.WriteLine("New client ({0}) connected", clientIndex); using (client) { var buf = new byte[4096]; var stream = client.GetStream(); while (!ct.IsCancellationRequested) { //under some circumstances, it's not possible to detect //a client disconnecting if there's no data being sent //so it's a good idea to give them a timeout to ensure that //we clean them up. var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15)); var amountReadTask = stream.ReadAsync(buf, 0, buf.Length, ct); var completedTask = await Task.WhenAny(timeoutTask, amountReadTask) .ConfigureAwait(false); if (completedTask == timeoutTask) { var msg = Encoding.ASCII.GetBytes("Client timed out"); await stream.WriteAsync(msg, 0, msg.Length); break; } //now we know that the amountTask is complete so //we can ask for its Result without blocking var amountRead = amountReadTask.Result; if (amountRead == 0) break; //end of stream. await stream.WriteAsync(buf, 0, amountRead, ct) .ConfigureAwait(false); } } Console.WriteLine("Client ({0}) disconnected", clientIndex); }
...或者迁移到异步/等待已经取代它们的方法,就像我的例子一样. (3认同)
Stephen Clea.. 14
您可以使用TaskFactory.FromAsync
自动换行Begin
/ End
成对async
操作.
Stephen Toub 在他的博客上有一个等待Socket
更高效的*Async
端点的等待.我建议将其与TPL Dataflow结合使用,以创建完全async
兼容的Socket
组件.
...因为你如此坚定,我汇总了一个非常简单的例子,说明如何编写一个echo服务器来帮助你.收到的任何内容都会回复给客户端.服务器将保持运行60秒.尝试在localhost端口6666上telnet到它.花点时间了解这里发生了什么.
void Main() { CancellationTokenSource cts = new CancellationTokenSource(); TcpListener listener = new TcpListener(IPAddress.Any, 6666); try { listener.Start(); //just fire and forget. We break from the "forgotten" async loops //in AcceptClientsAsync using a CancellationToken from `cts` AcceptClientsAsync(listener, cts.Token); Thread.Sleep(60000); //block here to hold open the server } finally { cts.Cancel(); listener.Stop(); } } async Task AcceptClientsAsync(TcpListener listener, CancellationToken ct) { var clientCounter = 0; while (!ct.IsCancellationRequested) { TcpClient client = await listener.AcceptTcpClientAsync() .ConfigureAwait(false); clientCounter++; //once again, just fire and forget, and use the CancellationToken //to signal to the "forgotten" async invocation. EchoAsync(client, clientCounter, ct); } } async Task EchoAsync(TcpClient client, int clientIndex, CancellationToken ct) { Console.WriteLine("New client ({0}) connected", clientIndex); using (client) { var buf = new byte[4096]; var stream = client.GetStream(); while (!ct.IsCancellationRequested) { //under some circumstances, it's not possible to detect //a client disconnecting if there's no data being sent //so it's a good idea to give them a timeout to ensure that //we clean them up. var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15)); var amountReadTask = stream.ReadAsync(buf, 0, buf.Length, ct); var completedTask = await Task.WhenAny(timeoutTask, amountReadTask) .ConfigureAwait(false); if (completedTask == timeoutTask) { var msg = Encoding.ASCII.GetBytes("Client timed out"); await stream.WriteAsync(msg, 0, msg.Length); break; } //now we know that the amountTask is complete so //we can ask for its Result without blocking var amountRead = amountReadTask.Result; if (amountRead == 0) break; //end of stream. await stream.WriteAsync(buf, 0, amountRead, ct) .ConfigureAwait(false); } } Console.WriteLine("Client ({0}) disconnected", clientIndex); }
您可以使用TaskFactory.FromAsync
自动换行Begin
/ End
成对async
操作.
Stephen Toub 在他的博客上有一个等待Socket
更高效的*Async
端点的等待.我建议将其与TPL Dataflow结合使用,以创建完全async
兼容的Socket
组件.