I've previously used BeginAccept()
and BeginRead()
, but with Visual Studio 2012 I want to make use of the new asynchronous (async
, await
) features in my socket server program.
How can I complete the AcceptAsync
and ReceiveAsync
functions?
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() { } } }
An asynchronous client socket does not suspend the application while waiting for network operations to complete. Instead, it uses the standard . NET Framework asynchronous programming model to process the network connection on one thread while the application continues to run on the original thread.
Net. Sockets. SocketAsyncEventArgs) method starts an asynchronous request for a connection to the remote host. If you are using a connectionless protocol, ConnectAsync establishes a default remote host specified by the socketType and protocolType parameters.
You can read data asynchronously with the TCP/IP object in one of these two ways: Continuously, by setting ReadAsyncMode to continuous . In this mode, data is automatically stored in the input buffer as it becomes available from the server. Manually, by setting ReadAsyncMode to manual .
Socket programming is a way of connecting two nodes on a network to communicate with each other. Basically, it is a one-way Client and Server setup where a Client connects, sends messages to the server and the server shows them using socket connection.
...because you're so determined, I put together a very simple example of how to write an echo server to get you on your way. Anything received gets echoed back to the client. The server will stay running for 60s. Try telnetting to it on localhost port 6666. Take time to understand exactly what's going on here.
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With