Hang-up on async TCP client connection - c#

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.

Related

Why does this application not hang and how is it waiting for a client to connect?

I am learning some basic C# programming.
Was following a tutorial and the main function has a loop like this:
class Server
{
static List<Client> _clients = new();
static TcpListener _listener = new(IPAddress.Parse("127.0.0.1"),7892);
static void Main(string[] args)
{
_listener.Start();
while (true)
{
var client = new Client(_listener.AcceptTcpClient());
_clients.Add(client);
Console.WriteLine(_clients.Count+ " total clients");
}
}
}
Since this is an infinite never ending while loop, why does the program not hang like it does when I accidently create an infinite loop in other scripts?
Additionally, when I ran this code, I was surprised to find it was not adding a new client every loop, but only when a client connected, how exactly is it waiting on the AcceptTcpClient() function? I looked at the code for this function, its not clear to me how its waiting...
public TcpClient AcceptTcpClient()
{
if (!_active)
{
throw new InvalidOperationException(SR.net_stopped);
}
Socket acceptedSocket = _serverSocket!.Accept();
return new TcpClient(acceptedSocket);
}
Hint: in the future, putting a debugger breakpoint can help you find out why easily.
The AcceptTcpClient method is a blocking call, similar to Console.ReadLine():
// Perform a blocking call to accept requests.
// You could also use server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
So while your while loop would run forever, it doesn't consume resources (usually CPU) continously like this loop:
while (true) i++;
If you put a debugger, you will notice it stops at AcceptTcpClient until a client connects. That's why your program doesn't freeze since it's waiting and not doing anything. However note that if you do this in an UI thread of a WPF app for example, the GUI would probably freeze since it blocks the thread.
If you are curious about how blocking function is implemented, this question is probably the closest I could find on SO but nowadays people generally want to avoid it (since it blocks your thread) and try making things asynchronous (using Task) instead. You should actually use AcceptTcpClientAsync if possible.

How to prevent HttpListener from aborting pending requests on stoppage? HttpListener.Stop is not working

I have a problem here. In below code the async/await pattern is used with HttpListener. When the request is sent via HTTP "delay" query string argument is expected and its value causes the server to delay the mentioned request processing for the given period. I need the server to process the pending requests even after the server stopped receiving new requests.
static void Main(string[] args)
{
HttpListener httpListener = new HttpListener();
CountdownEvent sessions = new CountdownEvent(1);
bool stopRequested = false;
httpListener.Prefixes.Add("http://+:9000/GetData/");
httpListener.Start();
Task listenerTask = Task.Run(async () =>
{
while (true)
{
try
{
var context = await httpListener.GetContextAsync();
sessions.AddCount();
Task childTask = Task.Run(async () =>
{
try
{
Console.WriteLine($"Request accepted: {context.Request.RawUrl}");
int delay = int.Parse(context.Request.QueryString["delay"]);
await Task.Delay(delay);
using (StreamWriter sw = new StreamWriter(context.Response.OutputStream, Encoding.Default, 4096, true))
{
await sw.WriteAsync("<html><body><h1>Hello world</h1></body></html>");
}
context.Response.Close();
}
finally
{
sessions.Signal();
}
});
}
catch (HttpListenerException ex)
{
if (stopRequested && ex.ErrorCode == 995)
{
break;
}
throw;
}
}
});
Console.WriteLine("Server is running. ENTER to stop...");
Console.ReadLine();
sessions.Signal();
stopRequested = true;
httpListener.Stop();
Console.WriteLine("Stopped accepting requests. Waiting for the pendings...");
listenerTask.Wait();
sessions.Wait();
Console.WriteLine("Finished");
Console.ReadLine();
httpListener.Close();
}
The exact problem here, is that when the server is stopped the HttpListener.Stop is called, but all the pending requests are aborted immediately, i.e. the code is unable to send the responses back.
In non-async/await pattern (i.e. simple Thread based implementation) I have a choice to abort the thread (which I suppose is very bad) and this will allow me to process pending requests, because this simply Aborts HttpListener.GetContext call.
Can you please point me out, what am I doing wrong and how to can I prevent HttpListener to abort pending requests in async/await pattern?
It seems that when HttpListener closes the request queue handle, the requests in progress are aborted. As far as I can tell, there is no way to avoid having HttpListener do that - apparently, it's a compatibility thing. In any case, that's how its GetContext-ending system works - when the handle is closed, the native method GetContext call to actually get the request context returns an error immediately.
Thread.Abort doesn't help - really, I've yet to see a place where Thread.Abort is used correctly outside of the "application domain unloading" scenario. Thread.Abort can only ever abort managed code. Since your code is currently running native, it will only be aborted when it returns back to managed code - which is almost exactly equivalent to just doing this:
var context = await httpListener.GetContextAsync();
if (stopRequested) return;
... and since there's no better cancellation API for HttpListener, this is really your only option if you want to stick with HttpListener.
The shutdown will look like this:
stopRequested = true;
sessions.Wait();
httpListener.Dispose();
listenerTask.Wait();
I'd also suggest using CancellationToken instead of a bool flag - it handles all the synchronization woes for you. If that's not desirable for some reason, make sure you synchronize access to the flag - contractually, the compiler is allowed to omit the check, since it's impossible for the flag to change in single-threaded code.
If you want to, you can make listenerTask complete sooner by sending a dummy HTTP request to yourself right after setting stopRequested - this will cause GetContext to return immediately with the new request, and you can return. This is an approach that's commonly used when dealing with APIs that don't support "nice" cancellation, e.g. UdpClient.Receive.

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.

Will ManualResetEvent block the entire program?

I have a program that begins itself by listening for connections. I wanted to implement a pattern in which the server would accept a connection, pass that individual connection to a user class for processing: future packet reception, and handling of the data.
I ran into trouble with the synchronous pattern before I found out that asynchronous use of the Socket class isn't scary. But then I ran into more trouble. It seemed that, in a while (true) loop, since BeginAccept() is asynchronous, the program would constantly move through this loop and eventually run into an OutOfMemoryException. I needed something to listen for a connection, and immediately hand off responsibility of that connection to some other class.
So I read Microsoft's example and found out about ManualResetEvent. I could actually specify when I was ready for the loop to begin listening again! But after reading some questions here on Stack Overflow, I have become confused.
My worry is that even though I have asynchronously accepted a connection, the entire program will block while it's trying to listen for a new connection upon re-entering the loop. This isn't ideal if I'm handling multiple users.
I'm very new to the world of asynchronous I/O, so I would appreciate even the angriest of comments about my vocabulary or a misuse of a phrase.
Code:
static void Main(string[] args)
{
MainSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
MainSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.74"), 1626));
MainSocket.Listen(10);
while (true)
{
Ready.Reset();
AcceptCallback = new AsyncCallback(ConnectionAccepted);
MainSocket.BeginAccept(AcceptCallback, MainSocket);
Ready.WaitOne();
}
}
static void ConnectionAccepted(IAsyncResult IAr)
{
Ready.Set();
Connection UserConnection = new Connection(MainSocket.EndAccept(IAr));
}
The Microsoft example, in which they use the old-style WaitHandle based events, will work but frankly it is a very odd and awkward way to implement asynchronous code. I get the feeling that the events are there in the example mainly as a way of artificially synchronizing the main thread so it has something to do. But it's not really the right approach.
One option is to just not even accept sockets asynchronously. Instead, use the asynchronous I/O for when the socket is connected and use a synchronous loop in the main thread to accept sockets. This winds up being pretty much exactly what the Microsoft sample does anyway, but keeps all of the accept logic in the main thread instead of switching back and forth between the main thread (which starts the accept operation) and some IOCP thread that handles the completion.
Another option is to just give the main thread something else to do. For a simple example, this could be simply waiting for some user input to signal that the program should shut down. Of course, in a real program the main thread could be something useful (e.g. handling the message loop in a GUI program).
If the main thread is given something else to do, then you can use the asynchronous BeginAccept() in the way it was intended: you call the method to start the accept operation, and then don't call it again until that operation completes. The initial call happens when you initialize your server, but all subsequent calls happen in the completion callback.
In that case, your completion callback method looks more like this:
static void ConnectionAccepted(IAsyncResult IAr)
{
Connection UserConnection = new Connection(MainSocket.EndAccept(IAr));
MainSocket.BeginAccept(ConnectionAccepted, MainSocket);
}
That is, you simply call the BeginAccept() method in the completion callback itself. (Note that there's no need to create the AsyncCallback object explicitly; the compiler will implicitly convert the method name to the correct delegate type instance on your behalf).

C# Socket.BeginSend Sometimes Seems to Behave Synchronously?

While attempting to send a message for a queue through the BeginSend call seem te behave as a blocking call.
Specificly I have:
public void Send(MyMessage message)
{
lock(SEND_LOCK){
var state = ...
try {
log.Info("Begin Sending...");
socket.BeginSend(message.AsBytes(),0, message.ByteLength, SocketFlags.None,
(r) => EndSend(r), state);
log.Info("Begin Send Complete.");
}
catch (SocketException e) {
...
}
}
}
The callback would be something like this:
private void EndSend(IAsyncResult result) {
log.Info("EndSend: Ending send.");
var state = (MySendState) result.AsyncState;
...
state.Socket.EndSend(result, out code);
log.Info("EndSend: Send ended.");
WaitUntilNewMessageInQueue();
SendNextMessage();
}
Most of the time this works fine, but sometimes it hangs. Logging indicates this happens when BeginSend en EndSend are excecuted on the same Thread. The WaitUntilNewMessageInQueue blocks until there is a new message in the queue, so when there is no new message it can wait quit a while.
As far as I can tell this should not really be a problem, but in the some cases BeginSend blocks causing a deadlock situation where EndSend is blocking on WaitUntilNewMessageInQueue (expected), but Send is blocking on BeginSend in return as it seems te be waiting for the EndSend callback te return (not expected).
This behaviour was not what I was expecting. Why does BeginSend sometimes block if the callback does not return in timely fashion?
First of all, why are you locking in your Send method? The lock will be released before the send is complete since you are using BeginSend. The result is that multiple sends can be executing at the same time.
Secondly, do not write (r) => EndSend(r), just write EndSend (without any parameters).
Thrid: You do not need to include the socket in your state. Your EndSend method is working like any other instance method. You can therefore access the socket field directly.
As for your deadlocks, it's hard to tell. You delegate may have something to do with it (optimizations by the compiler / runner). But I have no knowledge in that area.
Need more help? Post more code. but I suggest that you fix the issues above (all four of them) and try again first.
Which operating system are you running on?
Are you sure you're seeing what you think you're seeing?
The notes on the MSDN page say that Send() CAN block if there's no OS buffer space to initiate your async send unless you have put the socket in non blocking mode. Could that be the case? Are you potentially sending data very quickly and filling the TCP window to the peer? If you break into the debugger what does the call stack show?
The rest is speculation based on my understanding of the underlying native technologies involved...
The notes for Send() are likely wrong about I/O being cancelled if the thread exits, this almost certainly depends on the underlying OS as it's a low level IO Completion Port/overlapped I/O issue that changed with Windows Vista (see here: http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html) and given that they're wrong about that then they could be wrong about how the completions (calls to EndSend() are dispatched on later operating systems). From Vista onwards it's possible that the completions could be dispatched on the issuing thread if the .Net sockets wrapper is enabling the correct options on the socket (see here where I talk about FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)... However, if this were the case then it's likely that you'd see this behaviour a lot as initially most sends are likely to complete 'in line' and so you'd see most completions happening on the same thread - I'm pretty sure that this is NOT the case and that .Net does NOT enable this option without asking...
This is how you check if it completed synchronously so you avoid the callback on another thread.
For a single send:
var result = socket.BeginSend(...);
if (result.CompletedSynchronously)
{
socket.EndSend(result);
}
For a queue of multiple sends, you can just loop and finalize all synchronous sends:
while (true)
{
var result = socket.BeginSend(...);
if (!result.CompletedSynchronously)
{
break;
}
socket.EndSend(result);
}

Categories

Resources