ClientWebSocket.ConnectAsync closing immediately - c#

I'm implementing a small ClientWebSocket to send messages to the IPAddress.Loopback address of the computer so that a browser utility page can pick them up. however as soon as I connect, the client is immediately closed without message, reason, or exception.
ClientWebSocket cws;
Uri address = new Uri("ws://" + IPAddress.Loopback.ToString() + ":80/"
async void Start(){
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls |
SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
using (cws = new ClientWebSocket()) {
cws.Options.KeepAliveInterval = new TimeSpan(1, 0, 0);
//Start response listener loop
_ = Task.Run(() => async_ListenerLoop(receiveCancelTokenSrc.Token).ConfigureAwait(false));
try {
//Start the connection
cws.ConnectAsync(address, sendCancelTokenSrc.Token);
} catch(Exception ex) {
MessageBox.Show("Unable to connect.\n\r\n\r" + ex.Message);
}
}
}
async Task async_ListenerLoop(CancellationToken cancelToken) {
ArraySegment<byte> buffer = WebSocket.CreateServerBuffer(RECIEVE_BUFFER);
List<byte> rawData = new List<byte>();
try {
while (state != WebSocketState.Closed && state != WebSocketState.Aborted && !cancelToken.IsCancellationRequested) {
if(state == WebSocketState.Connecting) {
//Sometimes it waits 2-3 cycles, other times it closes immediately
await Task.Delay(500);
continue;
}
WebSocketReceiveResult receiveResult = await cws.ReceiveAsync(buffer, cancelToken);
if (!cancelToken.IsCancellationRequested) {
if (state == WebSocketState.CloseReceived && receiveResult.MessageType == WebSocketMessageType.Close) {
sendCancelTokenSrc.Cancel();
await cws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Acknowledge Close frame", CancellationToken.None);
//The socket state changes to closed at this point
}
if (state == WebSocketState.Open) {
if (receiveResult.MessageType == WebSocketMessageType.Text) {
rawData.AddRange(buffer.Array);
if (receiveResult.EndOfMessage) {
string strData = Encoding.UTF8.GetString(rawData.ToArray(), 0, rawData.Count);
ProcessData(JsonConvert.DeserializeObject<RequestDigest>(strData));
rawData.Clear();
}
} else if (receiveResult.MessageType == WebSocketMessageType.Binary) {
rawData.AddRange(buffer.Array);
if (receiveResult.EndOfMessage) {
ProcessData(rawData.ToArray());
rawData.Clear();
}
}
}
}
}
//Descripion is always null
MessageBox.Show("Connection was closed because '"+cws.CloseStatusDescription+"'");
} catch (OperationCanceledException ex) {
// normal upon task/token cancellation, disregard
MessageBox.Show("Connection to server cancelled.\n\r\n\r" + ex.Message);
} catch (JsonReaderException ex) {
MessageBox.Show("Unable to read incoming message.\n\r\n\r" + ex.Message);
} catch (Exception ex) {
MessageBox.Show("Unable recieve incoming message.\n\r\n\r" + ex.Message);
} finally {
sendCancelTokenSrc.Cancel();
AbortConnection();
}
}
void AbortConnection() {
// don't leave the socket in any potentially connected state
if (state != WebSocketState.Closed) {
cws.Abort();
}
cws.Dispose();
}

There may be other problems with your code (wiring up sockets and clients takes a bit of messing about before you get it right) but there are two glaring problems:
You need to await the result of ConnectAsync(...), to stop the code of Start() continuing synchronously without it:
await cws.ConnectAsync(address, sendCancelTokenSrc.Token);
And you need to make sure that cws does not get disposed until you've finished with it. The using(cws) { ... } block will dispose cws as soon as the code leaves the squiggly braces (which happens straight away currently), even though your listener is still running, and needs it to remain alive.
You can either do that by keeping the code within the using block by awaiting an asynchronous result (such as hint! a final result from your listener) - or by not using using at all and manually disposing cws yourself at the right time.
Also make sure to only start your listener after the connection call has completed, to ensure cws is in a good state.
Something like this:
using(cws = new ClientWebSocket())
{
await cws.ConnectAsync(...);
await DoSomeListeningForABit();
} //cws gets implicitly disposed here
And... your listener will doubtlessly require more work too, but the above will get you past your immediate problem (hopefully!)

Related

Async function freezes UI thread

I have an async function which still freezes / lags the UI thread for me when I execute it. This is my function calling it.
private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});
}
And this is the async function that freezes my UI Thread
public static async Task<string> getJsonFromURL(string url)
{
try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
I already tried to make everything in TcpListenerLogic run in a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();
Which resulted in the whole UI completely freezing. And I tried to make TcpListenerLogic async and await the dispatcher, which also made everything freeze permanently. I also tried to make TcpListenerLogic async and leave the dispatcher. The dispatcher is only there because I normally have some UI code in there, which I left out for my tests.
I have ventured far through the internet, but no BackgroundWorker, ThreadPool or other methods helped me in my endeavour.
If anyone has help for this particular problem, or a resource that would improve my understanding of async functions in C#, I would much appreciate it.
Edit
As requested a deeper insight in how this event handler is called.
I have System.Net.Websocket, which is connected to the Backend API I am working with and triggers an event, everytime he receives new Data. To guarantee the socket listens as longs as it is open, there is a while loop which checks for the client state:
public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{ // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}
The Event has a handler attached:
TcpReceived += TcpListener_TcpReceived;
And this is the Handler, which calls the previously seen "TcpListenereLogic".
private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
// TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
// Thread.CurrentThread.IsBackground = true;
// TcpListenerLogic(sender, e);
//}).Start();
}
I previously had the "TcpListenereLogic" as the handler, but I wanted to try different methods to call it. I also left in the commented out part, to show how the call of "TcpListenereLogic" looked already. All my attempts were with all mentioned setups and sadly lead to nothing.
Thank you very much #TheodorZoulias for helping me to find the solution to my problem.
It turns out it wasn't the async function itself, but rather how often it gets called. It got called roughly ~120 times every second.
My solution starts by calling the Listener method over a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();
To limit the amount of calls that happen every second I added a dispatcher timer, that resets a bool after it has been used for a call, by my Event.
readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer =
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();
Then I wrapped everything inside the while loop into an if condition based on the bool, the most important part was to have my "event EventHandler TcpReceived" in there:
// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}
I added my TcpListenerLogic to the Eventhandler:
TcpReceived += TcpListenerLogic;
And my TcpListenerLogic now looked like this (names have been changed):
private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}
Adding a new Thread to execute any step results in problems, so keep in mind that all this uses the thread created at the beginning for "StartListener"

How to stop reading from stream on a disconnect gracefully?

I have a simple socket connection that runs a read task in async. When I disconnect I get an exception:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'SslStream'.
I don't know how to stop it trying to read when it is sitting and waiting to read a message when I call disconnect. This is my read code:
public async Task<int> Read(byte[] readBuffer)
{
if (!IsConnected)
{
return 0;
}
try
{
await Stream.ReadAsync(_header, 0, _header.Length);
return await Stream.ReadAsync(readBuffer, 0, _header[0]);
}
catch (Exception e)
{
Debug.Log(e);
Disconnect();
return 0;
}
}
protected async Task _RunReader()
{
var totalBytes = await Read(_readBuffer);
if (totalBytes > 0)
{
HandleReader(_readBuffer, totalBytes);
_RunReader();
}
}
And this is my disconnect code:
public async Task Disconnect(bool graceful = false)
{
if (IsConnected && graceful)
{
lockPackets = true;
Empty[0] = 1; // send disconnect message to server for graceful
await Send(Empty,1);
}
Stream?.Close();
TcpClient.Close();
IsConnected = false;
}
Is there any way to abandon ReadAsync when Disconnect is called to avoid getting an exception? It doesn't effect the program since I try catch, but I feel like there's probably a more elegant way than just allowing it throw silent exceptions?

How can I gracefully terminate a BLOCKED thread?

There are plenty of places that deal with terminating C# threads gracefully. However, they rely on a loop or if condition executing inside a loop, which assumes that this statement will be executed frequently; thus, when the stop bool flag is set, the thread exits quickly.
What if I have a thread in which this is not true? In my case, this is a thread set up to receive from a server, which frequently blocks on a call to read data from the input stream, where none is yet provided so it waits.
Here is the thread in question's loop:
while (true)
{
if (EndThread || Commands.EndRcvThread)
{
Console.WriteLine("Ending thread.");
return;
}
data = "";
received = new byte[4096];
int bytesRead = 0;
try
{
bytesRead = stream.Read(received, 0, 4096);
}
catch (Exception e)
{
Output.Message(ConsoleColor.DarkRed, "Could not get a response from the server.");
if (e.GetType() == Type.GetType("System.IO.IOException"))
{
Output.Message(ConsoleColor.DarkRed, "It is likely that the server has shut down.");
}
}
if (bytesRead == 0)
{
break;
}
int endIndex = received.Length - 1;
while (endIndex >= 0 && received[endIndex] == 0)
{
endIndex--;
}
byte[] finalMessage = new byte[endIndex + 1];
Array.Copy(received, 0, finalMessage, 0, endIndex + 1);
data = Encoding.ASCII.GetString(finalMessage);
try
{
ProcessMessage(data);
}
catch (Exception e)
{
Output.Message(ConsoleColor.DarkRed, "Could not process the server's response (" + data + "): " + e.Message);
}
}
The if statement at the top of the block does what the usual stopping-a-thread-gracefully setup does: checks a flag, terminates the thread if it's set. However, this thread is usually to be found waiting a few lines further down, at stream.Read.
Given this, is there any way to gracefully terminate this thread (i.e. no Aborting), and clean up its resources (there's a client that needs to be closed)?
Assuming you can use async / Tasks, the way to do clean stopping of async and IO operations is with a CancelationToken that is connected to a CancelationTokenSource. The below code snippet illustrates a simplified example of its usage when applied to a simplified version of your code.
class MyNetworkThingy
{
public async Task ReceiveAndProcessStuffUntilCancelled(Stream stream, CancellationToken token)
{
var received = new byte[4096];
while (!token.IsCancellationRequested)
{
try
{
var bytesRead = await stream.ReadAsync(received, 0, 4096, token);
if (bytesRead == 0 || !DoMessageProcessing(received, bytesRead))
break; // done.
}
catch (OperationCanceledException)
{
break; // operation was canceled.
}
catch (Exception e)
{
// report error & decide if you want to give up or retry.
}
}
}
private bool DoMessageProcessing(byte[] buffer, int nBytes)
{
try
{
// Your processing code.
// You could also make this async in case it does any I/O.
return true;
}
catch (Exception e)
{
// report error, and decide what to do.
// return false if the task should not
// continue.
return false;
}
}
}
class Program
{
public static void Main(params string[] args)
{
using (var cancelSource = new CancellationTokenSource())
using (var myStream = /* create the stream */)
{
var receive = new MyNetworkThingy().ReceiveAndProcessStuffUntilCancelled(myStream, cancelSource.Token);
Console.WriteLine("Press <ENTER> to stop");
Console.ReadLine();
cancelSource.Cancel();
receive.Wait();
}
}
}
.

Proper way to handle a continuous TCPClient ReadAsync Networkstream exception

I have an application that runs a background thread which communicates to multiple devices. The devices send me data based off an external trigger that I do not control. I have to wait for the devices to send me data and operate on them. If an exception occurs, I need to display that on the UI.
I am attempting to continuously read data over the network stream. When data comes, I need to raise it as an event and then start reading again. I need to be able to handle if an exception is thrown such as the device being disconnected.
At the base I have a network stream reading asynchronously
public Task<string> ReadLinesAsync(CancellationToken token)
{
_readBuffer = new byte[c_readBufferSize];
// start asynchronously reading data
Task<int> streamTask = _networkstream.ReadAsync(_readBuffer, 0, c_readBufferSize, token);
// wait for data to arrive
Task<String> resultTask = streamTask.ContinueWith<String>(antecedent =>
{
// resize the result to the size of the data that was returned
Array.Resize(ref _readBuffer, streamTask.Result);
// convert returned data to string
var result = Encoding.ASCII.GetString(_readBuffer);
return result; // return read string
}, token);
return resultTask;
}
So the way I am trying to do this is on start up, I start a thread that is reading by running the Start() method. But when an exception is thrown it kills my program even though I put some error trapping around it. I have been attempting to trap it at different places just to see what happens but I have not been able to figure out the proper way to do this so that I can raise the error to the UI without bombing out my application.
async public override void Start()
{
try
{
await _client.ReadLinesAsync(_cts.Token).ContinueWith(ReadLinesOnContinuationAction, _cts.Token);
}
catch (AggregateException ae)
{
ae.Handle((exc) =>
{
if (exc is TaskCanceledException)
{
_log.Info(Name + " - Start() - AggregateException"
+ " - OperationCanceledException Handled.");
return true;
}
else
{
_log.Error(Name + " - Start() - AggregateException - Unhandled Exception"
+ exc.Message, ae);
return false;
}
});
}
catch (Exception ex)
{
_log.Error(Name + " - Start() - unhandled exception.", ex);
}
}
async private void ReadLinesOnContinuationAction(Task<String> text)
{
try
{
DataHasBeenReceived = true;
IsConnected = true;
_readLines.Append(text.Result);
if (OnLineRead != null) OnLineRead(Name, _readLines.ToString());
_readLines.Clear();
await _client.ReadLinesAsync(_cts.Token).ContinueWith(ReadLinesOnContinuationAction, _cts.Token);
}
catch (Exception)
{
_log.Error(Name + " - ReadLinesOnContinuationAction()");
}
}
The debugger usually stops on the line:
_readLines.Append(text.Result);
I tried putting this within a check for the text.IsFaulted flag but then I bombed out on the .ContinueWith.
Does anyone have any ideas on what I need to fix this so that I can properly catch the error and raise the even to the UI? This code has all kinds of bad smells to it but I am learning this as I go along. Thanks for any help you can give.
Bombed out with which ContinueWith? You have at least two that I see.
Personally, I would not mix async/await with ContinueWith. The await is already giving you a convenient way to do a ContinueWith, so just use that. For example:
public async Task<string> ReadLinesAsync(CancellationToken token)
{
_readBuffer = new byte[c_readBufferSize];
// start asynchronously reading data
int readResult = await _networkstream.ReadAsync(_readBuffer, 0, c_readBufferSize, token);
// after data arrives...
// resize the result to the size of the data that was returned
Array.Resize(ref _readBuffer, streamTask.Result);
// convert returned data to string
return Encoding.ASCII.GetString(_readBuffer);
}
async public override void Start()
{
try
{
string text = await _client.ReadLinesAsync(_cts.Token);
await ReadLinesOnContinuationAction(text);
}
catch (AggregateException ae)
{
ae.Handle((exc) =>
{
if (exc is TaskCanceledException)
{
_log.Info(Name + " - Start() - AggregateException"
+ " - OperationCanceledException Handled.");
return true;
}
else
{
_log.Error(Name + " - Start() - AggregateException - Unhandled Exception"
+ exc.Message, ae);
return false;
}
});
}
catch (Exception ex)
{
_log.Error(Name + " - Start() - unhandled exception.", ex);
}
}
async private Task ReadLinesOnContinuationAction(Task<String> text)
{
try
{
DataHasBeenReceived = true;
IsConnected = true;
_readLines.Append(text.Result);
if (OnLineRead != null) OnLineRead(Name, _readLines.ToString());
_readLines.Clear();
string text = await _client.ReadLinesAsync(_cts.Token);
await ReadLinesOnContinuationAction(text);
}
catch (Exception)
{
_log.Error(Name + " - ReadLinesOnContinuationAction()");
}
}
Or something like that. The above is obviously not compiled and might require a little bit of massaging to get right. But hopefully the general idea is clear enough.

Async operation completes, but result is not send to browser

I want to implement a webchat.
The backend is a dual WCF channel. Dual channel works in the console or winforms,
and it actually works on the web. I can at least send and receive messages.
As a base I used this blog post
so, the async operation completes.
When i debug the result, I see that the messages are all ready to send to the browser.
[AsyncTimeout(ChatServer.MaxWaitSeconds * 1020)] // timeout is a bit longer than the internal wait
public void IndexAsync()
{
ChatSession chatSession = this.GetChatSession();
if (chatSession != null)
{
this.AsyncManager.OutstandingOperations.Increment();
try
{
chatSession.CheckForMessagesAsync(msgs =>
{
this.AsyncManager.Parameters["response"] = new ChatResponse { Messages = msgs };
this.AsyncManager.OutstandingOperations.Decrement();
});
}
catch (Exception ex)
{
Logger.ErrorException("Failed to check for messages.", ex);
}
}
}
public ActionResult IndexCompleted(ChatResponse response)
{
try
{
if (response != null)
{
Logger.Debug("Async request completed. Number of messages: {0}", response.Messages.Count);
}
JsonResult retval = this.Json(response);
Logger.Debug("Rendered response: {0}", retval.);
return retval;
}
catch (Exception ex)
{
Logger.ErrorException("Failed rendering the response.", ex);
return this.Json(null);
}
}
But nothing is actually sent.
Checking Fiddler, I see the request but I never get a response.
[SessionState(SessionStateBehavior.ReadOnly)]
public class ChatController : AsyncController
I also had to set the SessionStateBehaviour to Readonly, otherwise the async operation would block the whole page.
EDIT:
Here is the CheckForMessagesAsync:
public void CheckForMessagesAsync(Action<List<ChatMessage>> onMessages)
{
if (onMessages == null)
throw new ArgumentNullException("onMessages");
Task task = Task.Factory.StartNew(state =>
{
List<ChatMessage> msgs = new List<ChatMessage>();
ManualResetEventSlim wait = new ManualResetEventSlim(false);
Action<List<ChatMessage>> callback = state as Action<List<ChatMessage>>;
if (callback != null)
{
IDisposable subscriber = m_messages.Subscribe(chatMessage =>
{
msgs.Add(chatMessage);
wait.Set();
});
bool success;
using (subscriber)
{
// Wait for the max seconds for a new msg
success = wait.Wait(TimeSpan.FromSeconds(ChatServer.MaxWaitSeconds));
}
if (success) this.SafeCallOnMessages(callback, msgs);
else this.SafeCallOnMessages(callback, null);
}
}, onMessages);
}
private void SafeCallOnMessages(Action<List<ChatMessage>> onMessages, List<ChatMessage> messages)
{
if (onMessages != null)
{
if (messages == null)
messages = new List<ChatMessage>();
try
{
onMessages(messages);
}
catch (Exception ex)
{
this.Logger.ErrorException("Failed to call OnMessages callback.", ex);
}
}
}
it`s the same idea as the in the refered blog post
EDIT2:
Btw, when nothing is received, so the wait timeout comes into play, the reponse returns. so it seems to crash somewhere. any idea how to log this?
I changed the jQUERY request (see original blog post) from POST to GET. That fixes it.

Categories

Resources