async- await until someone tries to connect - c#

I want to create an async method that awaits until someone will try to connect
something that will look like
await (listener.Pending() == true);
of course, that won't work.
How can I do that?

If you can use async/await then potentially you are using .NET 4.5. If so you can use the AcceptSocketAsync or AcceptTcpClientAsync methods on TcpListener? For example:
await listener.AcceptSocketAsync();
The Pending method does the same checks as these two methods but just returns immediately with a true/false. The two Accept...Async are designed to block until Pending would otherwise return true and then hand you your Socket or TcpClient respectively.
Background
From the Pending documentation:
This non-blocking method determines if there are any pending connection requests. Because the AcceptSocket and AcceptTcpClient methods block execution until the Start method has queued an incoming connection request, the Pending method can be used to determine if connections are available before attempting to accept them.
The Accept...Async methods do the same as the Accept... versions, but you can await them.

You can create a Task from Begin\EndAccept:
var listener = new TcpListener(...);
Task<Socket> acceptTask = Task.Factory.FromAsync<Socket>(listener.BeginAcceptSocket, listener.EndAcceptSocket, null);
var socket = await acceptTask;

Related

Understanding async/await to manage multiple clients

I'm getting confused by await/async as I may still not get the point of its correct usage.
I have a simple WPF-UI and a ViewModel-method to start listening for clients which want to connect.
The following method is executed when the user clicks the button to start listening:
public void StartListening()
{
_tcpListener.Start(); // TcpListener
IsListening = true; // bool
Task.Factory.StartNew(DoStartListeningAsync, TaskCreationOptions.LongRunning);
}
The method DoStartListeningAsync which is called is defined like
private async Task DoStartListeningAsync()
{
while (IsListening)
{
using (var newClient = await _tcpListener.AcceptTcpClientAsync() /*.WithWaitCancellation(_cts.Token)*/)
{
apiClient = new ApiClient();
if(await apiClient.InitClientAsync()) // <-- here is the problem
{
// ... apiClient is now initialized
}
// ... do more and go back to await _tcpListener.AcceptTcpClientAsync()
}
}
}
The ApiClient class' InitClientAsync method is defined like:
public async Task<bool> InitClientAsync()
{
using (var requestStream = await _apiWebRequest.GetRequestStreamAsync())
{
_apiStreamWriter = new StreamWriter(requestStream);
}
// ... do somehing with the _apiStreamWriter
return true;
}
However, sometimes the InitClientAsync-call will get stuck at await _apiWebRequest.GetRequestStreamAsync() which then will freeze the execution of the DoStartListeningAsync-method at // <-- here is the problem.
In case the DoStartListeningAsync is stuck, no new connections will be handled which destroys my whole concept of handling multiple clients asynchronously.
Since you are using "await" keyword along the code path, you won't actually serve
multiple clients asynchronously.
The thing is, your code in the background thread will serve clients one by one. Take a deeper look - in the while loop you are getting request stream, wait till it is loaded, serve it, and then wait for other request stream.
async/await principle doesn't itself provide ability to serve multiple actions at the time. The only thing it is doing - prevents blocking current thread from being reusable by other code. So if going with async/await, you allow system yo use your current task thread, while it is waiting to other async action to complete (like _apiWebRequest.GetRequestStreamAsync()).
But since you are having one task, and you are waiting on every iteration of while loop - your code will work the same way, if you wrote it completely synchronous. The only profit is that you are using Task, and so .Net can reuse it's thread from thread pool while you are waiting for async actions to complete.
If you wan't to serve multiple clients asynchronously, you should either start multiple tasks, or don't wait till request is completely served - so actually remove some awaits from your code.
So you should move towards design, there you have one listening task/thread, that does nothing exept reading requests and putting it to the some queue. And having other tasks, that serve requests, reading it from the queue.
If I understood you correctly, you are using TcpListener under the hood. So what you need, is the loop where you accept new clients, and start serving them in the different thread/task without any waiting, so going directly to accepting other clients. But you can and should use async/await inside those handlers that serve clients.
Take a look at this answer - not completely your case (since I don't know all details of implementation), but just to get the idea.

Socket.ConnectAsync for windows store application does not like Async

Windows store applications are frustrating to say the least; just close enough to regular .net to get into trouble.
My issue with working in Tasks, await, and Socket.ConnectAsync.
I've got the following code:
public async Task<string> Connect(string hostName, int portNumber)
{
string result = string.Empty;
// Create DnsEndPoint. The hostName and port are passed in to this method.
DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);
// Create a stream-based, TCP socket using the InterNetwork Address Family.
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Create a SocketAsyncEventArgs object to be used in the connection request
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = hostEntry;
// Inline event handler for the Completed event.
// Note: This event handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
// Retrieve the result of this request
result = e.SocketError.ToString();
// Signal that the request is complete, unblocking the UI thread
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Connect request over the socket
await _socket.ConnectAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
return result;
}
And I started added in Async / await to the app to prevent UI issues. But when I went into this function and added the Await to
await _socket.ConnectAsync(socketEventArg);
I get the error:
Error CS1929 'bool' does not contain a definition for 'GetAwaiter' and the best extension method overload 'WindowsRuntimeSystemExtensions.GetAwaiter(IAsyncAction)' requires a receiver of type 'IAsyncAction'
In looking at the docs for ConnectAsync it looks like ConnectAsync is supposed to support await...
Does it not support await?
No, ConnectAsync is not a TAP method, and thus cannot be used with await.
My #1 recommendation for anyone using raw sockets is "don't". If you can, use a REST API (with HttpClient) or a SignalR API. Raw sockets have tons of pitfalls.
If you must use raw sockets (i.e., the other side is using a custom TCP/IP protocol and you don't have the power to fix the situation), then the first thing to note is that the Socket class has three complete APIs all in one class.
The first is the deceptively simple-looking synchronous API (Connect), which I do not recommend for any production code. The second is the standard APM pattern (BeginConnect/EndConnect). The third is a specialized asynchronous pattern that is specific to the Socket class (ConnectAsync); this specialized API is much more complex to use than the standard asynchronous API, and is only necessary when you have chatty socket communication in a constrained environment, and need to reduce the object churn through the garbage collector.
Note that there is no await-compatible API. I haven't spoken to anyone at Microsoft about this, but my strong suspicion is that they simply thought the Socket class had too many members already (3 complete APIs; adding an await-compatible one would add a fourth complete API), and that's why it was skipped over when they added TAP-pattern (await-compatible) members to other types in the BCL.
The correct API to use - easily 99.999% of the time - is the APM one. You can create your own TAP wrappers (which work with await) by using TaskFactory.FromAsync. I like to do this with extension methods, like this:
public static Task ConnectTaskAsync(this Socket socket, EndPoint remoteEP)
{
return Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, remoteEP, null);
}
You can then invoke it anywhere on a Socket, as such:
await _socket.ConnectTaskAsync(hostEntry);

Use of Socket.BeginAccept/EndAccept for multiple connections

Unlike the synchronous Accept, BeginAccept doesn't provide a socket for the newly created connection. EndAccept however does, but it also stops future connections from being accepted; so I concocted the following code to allow multiple 'clients' to connect to my server:
serverSocket.BeginAccept(AcceptCallback, serverSocket);
AcceptCallback code:
void AcceptCallback(IAsyncResult result)
{
Socket server = (Socket)result.AsyncState;
Socket client = server.EndAccept(result);
// client socket logic...
server.BeginAccept(AcceptCallback, server); // <- continue accepting connections
}
Is there a better way to do this? It seems to be a bit 'hacky', as it essentially loops the async calls recursively.
Perhaps there is an overhead to having multiple calls to async methods, such as multiple threads being created?
The way are doing this is correct for using asynchronous sockets. Personally, I would move your BeginAccept to right after you get the socket from the AsyncState. This will allow you to accept additional connections right away. As it is right now, the handling code will run before you are ready to accept another connection.
As Usr mentioned, I believe you could re-write the code to use await with tasks.
This is normal when you deal with callback-based async IO. And it is what makes it so awful to use!
Can you use C# await? That would simplify this to a simple while (true) { await accept(); } loop.

How do you ensure that async methods will run asynchronously?

In .NET 4.0 I'm using the FtpWebRequest async methods.
One issue I'm running into is that I'd like a timeout option.
To achieve this I'm currently passing a ManualResetEvent around in the async state and then calling ResetEvent.WaitOne(30000) after initiating the request, ensuring the boolean response is true (or throwing a TimeoutException).
If my async methods run asynchronously, I believe this is fine, as they start in another thread, my current thread continues to the WaitOne, and then either the asynchronous methods complete or the timeout fires.
Something like this:
var ar = state.Request.BeginGetResponse(
new AsyncCallback(BeginGetResponseCallback),
state // has a ManualResetEvent
);
// Won't reach here if BeginGetResponse run synchronously
// as indicated by ar.CompletedSynchronously.
// The risk is then that BeginGet blocks infinitely
// without a timeout (as I'm seeing)
if (!state.ResetEvent.WaitOne((int)5000))
throw new TimeoutException();
However, if my async methods run synchronously (as indicated by CompletedSynchronously) then the WaitOne is never reached, and the thread blocks infinitely.
Is there a reliable way (perhaps a BackgroundWorker?) to ensure the Begin/End calls happen asynchronously, or alternatively a better and more reliable way to enforce a timeout?
Thanks
Have you considered simply using the FtpWebRequest.TimeOut property?
Something in the direction of:
FtpWebRequest request = null;
request.Timeout = 3000;
Func<WebResponse> responseDelegate = () => request.GetResponse();
var asynchRes = responseDelegate.BeginInvoke(null, null);
try
{
responseDelegate.EndInvoke(asynchRes);
}
catch (TimeoutException e)
{
// bla
}
Come to think of it, also try to specify the TimeOut and call the BeginGetResponse, it should work since it actually calls the Synchronous method behind the scenes.

Hang-up on async TCP client connection

I'm taking practice with the async CTP framework, and as exercise I would create a TCP client able to query a server (using an arbitrary protocol). Anyway, I'm stuck at the very early stage because an issue on the connection. Either I still didn't understand some basic point, or there is something strange.
So, here is the async connector:
public class TaskClient
{
public static Task<TcpClient> Connect(IPEndPoint endPoint)
{
//create a tcp client
var client = new TcpClient(AddressFamily.InterNetwork);
//define a function to return the client
Func<IAsyncResult, TcpClient> em = iar =>
{
var c = (TcpClient)iar.AsyncState;
c.EndConnect(iar);
return c;
};
//create a task to connect the end-point async
var t = Task<TcpClient>.Factory.FromAsync(
client.BeginConnect,
em,
endPoint.Address.ToString(),
endPoint.Port,
client);
return t;
}
}
I mean to call this function only once, then having back a TcpClient instance to use for any succeeding query (code not shown here).
Somewhere in my form, I call the function above as follows:
//this method runs on the UI thread, so can't block
private void TryConnect()
{
//create the end-point
var ep = new IPEndPoint(
IPAddress.Parse("192.168.14.112"), //this is not reachable: correct!
1601);
var t = TaskClient
.Connect(ep)
.ContinueWith<TcpClient>(_ =>
{
//tell me what's up
if (_.IsFaulted)
Console.WriteLine(_.Exception);
else
Console.WriteLine(_.Result.Connected);
return _.Result;
})
.ContinueWith(_ => _.Result.Close());
Console.WriteLine("connection in progress...");
//wait for 2" then abort the connection
//Thread.Sleep(2000);
//t.Result.Client.Close();
}
The test is to try to connect a remote server, but it has to be unreachable (PC on, but service stopped).
When I run the TryConnect function, it returns correctly "connection in progress..." as soon, then displays an exception because the remote endpoint is off. Excellent!
The problem is that it needs several seconds to return the exception, and I would like to give the chance to the user to cancel the operation in progress. According to the MSDN specs about the BeginConnect method, if you wish to abort the async operation, just call Close on the working socket.
So, I tried to add a couple of lines at the end (commented out as above), so to simulate the users cancellation after 2 seconds. The result looks as a hang of the app (hourglass). By pausing the IDE, it stops on the very last line t.Result.Client.Close(). However, by stopping the IDE everything closes normally, without any exception.
I've also tried to close the client directly as t.Result.Close(), but it's exactly the same.
It's me, or there's anything broken on the connection process?
Thanks a lot in advance.
t.Result.Close() will wait for the t task completion.
t.ContinueWith() will also wait for the completion of the task.
To cancel you must wait on 2 tasks: the tcp and a timer.
Using the async tcp syntax:
await Task.WhenAny(t,Task.Delay(QueryTimeout));
if (!t.IsCompleted)
tcpClient.Close(); //Cancel task
Try calling Dispose() on the object - it's a bit more agressive than Close(). You could look at the various Timeout members on the TcpClient class and set them to more appropriate values (e.g. 1 second in a LAN environment is probably good enough). You can also have a look at the CancellationTokenSource functionality in .Net 4.0. This allows you to signal to a Task that you wish it to discontinue - I found an article that might get you started.
You should also find out which thread is actually stalling (the primary thread might just be waiting for another thread that is stalled), e.g. the .ContinueWith(_ => _.Result.Close()) might be the problem (you should check what the behaviour is when closing a socket twice). While debugging open the Threads window (Debug -> Windows -> Threads) and have a look through each thread.

Categories

Resources