当前位置:  开发笔记 > 编程语言 > 正文

使用.Net 4.5异步功能进行套接字编程

如何解决《使用.Net4.5异步功能进行套接字编程》经验,为你挑选了2个好方法。

我以前使用过BeginAccept()BeginRead(),但与Visual Studio 2012我想利用新的异步的(async,await)功能在我的socket服务器程序.

我该如何完成AcceptAsyncReceiveAsync功能?

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组件.



1> spender..:

...因为你如此坚定,我汇总了一个非常简单的例子,说明如何编写一个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);
}


...或者迁移到异步/等待已经取代它们的方法,就像我的例子一样.

2> Stephen Clea..:

您可以使用TaskFactory.FromAsync自动换行Begin/ End成对async操作.

Stephen Toub 在他的博客上有一个等待Socket更高效的*Async端点的等待.我建议将其与TPL Dataflow结合使用,以创建完全async兼容的Socket组件.


`AcceptAsync`和`ReceiveAsync`使用[异步API的特殊形式](http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx),仅存在用于`插座`班.它们与`async`和`await`无关.
请点击我上次评论中的链接.MSDN页面上有一个很长的例子.MSDN套接字示例的常见注意事项适用:它可能无法正确处理边缘条件,并且几乎肯定需要针对任何类型的现实协议进行更改.
我不想包装开始和结束(如果我理解正确的话).我想要做的是使用.AcceptAsync而不是.BeginAccept,而.ReceiveAsync而不是.BeginReceive
:D是的,这就是我想要但我无法实现使用SocketAsyncEventArgs,我不知道如何.如果你能给我一个接受连接的例子,使用这些方法从他们那里接收数据,我将非常感激
推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有