Async/Await Sending and Receiving network Data - c#

I am attempting to wrap up both the sending and receiving of data to a server using the async/await pattern. What I have created is an event driven socket framework that fires events whenever data is received from the server. However, I am having trouble trying to figure out how to await the thread, after the send, so that I do not return until the data from the server returns.
In the past I used a manual reset event to achieve this...
byte[] returnData;
public byte[] SendData(byte[] data){
socket.Send(data, 0, data.Length);
manualResetEvent.Wait();
return returnData;
}
public void OnDataReceived(byte[] serverData){
returnData = serverData;
manualResetEvent.Set();
}
This method simply pauses the caller thread until the reset event is triggered. This is no good as I want the async/await pattern so that the calling thread is free to do other work while waiting for the data from the server.
What I have now is....
byte[] returnData;
public async Task<byte[]> SendData(byte[] data){
await socket.SendAsync(data, 0, data.Length);
//await something that frees up this thread to do other work
return returnData;
}
public void OnDataReceived(byte[] serverData){
returnData = serverData;
//do something that pushes SendData back into the active context
}
I think I am doing somethign wrong. Any help would be appreciated!

I have found a suitable solution.
Instead of using a ManualResetEvent, I can use what is called a TaskCompletionSource<T>. This gives me the functionality I need to allow the thread pool to wait for some state change.

Related

Replacing background worker with task/async/await?

I send a 7 byte TX command I am to receive a 7 byte RX response.
If possible, I'd like to chain the receive bytes task to send bytes task as this only seems logical.
I am aware that background workers are outdated and would like to modernize the code by utilizing the Task-Parallel-Library.
Can someone elucidate how to replace the backgroundWorker_DoWork event handler with an async task for the context described?
If you are always first sending bytes, and then receiving bytes, you could use something like this:
public static class NetworkStreamExtensions
{
public static async Task<byte[]> SendReceiveBytes(this NetworkStream self, byte[] toSend, int bytesToReceive, CancellationToken cancel)
{
await self.WriteAsync(toSend, 0, toSend.Length, cancel);
var receiveBuffer = new byte[bytesToReceive];
var receivedBytes = await self.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cancel);
if (receivedBytes != receiveBuffer.Length)
{
// Handle incorrect number of received bytes,
}
return receiveBuffer;
}
}
As this is using async/await it will use the current synchronization context to run the code. I.e. If called on the main thread, it will send and receive on the main thread. It will however permit other code to run between Writing and reading, since async methods does not block execution.

What is the proper way to use WebSocketClient ReceiveAsync and buffer?

I want to create a Bot class in C# for slack to let services create and consume messages for our company. To make it easy for our services to use, I have it just called with Connect() and use an event to let the caller know when there's a message. This is basically how it will be called:
SlackBot bot = new SlackBot(TOKEN);
bot.OnReceiveMessage += message => {
Console.WriteLine("DELEGATE GOT MESSAGE: '{0}'", message);
};
bot.Connect();
The Connect() method calls an internal Receive() method that calls itself after every message:
public delegate void MessageReceivedDelegate(string message);
public event MessageReceivedDelegate OnReceiveMessage;
void Receive()
{
_ReceiveTask = _Client.ReceiveAsync(_ClientBuffer, _CancellationToken);
_ReceiveTask.ContinueWith(twsrr =>
{
WebSocketReceiveResult result = twsrr.Result;
string message = Encoding.ASCII.GetString(_ClientBuffer.Array,
_ClientBuffer.Offset, result.Count);
OnReceiveMessage(message);
Receive();
});
}
So the largest buffer acceptable is 64k, do I need to check result.EndOfMessage and use a MemoryStream or something to to keep adding bytes to until I get the end of the message, then send it?
Looking at the RFC, that seems to be the case to me. I'm less familiar with the WebSocket protocol than the underlying TCP and other network protocols, but if on each call to ReceiveAsync() you actually received a complete message, there would not seem to be a need for the EndOfMessage property on the result.
Note also that your code could benefit from being written in the async/await pattern:
async Task Receive()
{
WebSocketReceiveResult result = await _Client.ReceiveAsync(_ClientBuffer, _CancellationToken);
if (result.Count != 0 || result.CloseStatus == WebSocketCloseStatus.Empty)
{
string message = Encoding.ASCII.GetString(_ClientBuffer.Array,
_ClientBuffer.Offset, result.Count);
OnReceiveMessage(message);
await Receive();
}
}
Or, if you prefer, change the Receive() to async but leave it as void and don't await it. It's an exception to the general rule for async methods, but it would avoid the I/O building a chain of continuations that only gets resolved when the connection is actually closed.

Server communication via async/await?

I want to create Socket message sending via TAP via async/await.
After reading this answer and this one - I decided to create a fully working sample :
So what have I tried :
I took the TAP extenstion methods from here (all ok) : and I test it in console cmd :
Reciever Code
public static class SocketExtensions
{
public static Task<int> ReceiveTaskAsync(this Socket socket, byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync<int>(
socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndReceive);
}
public static async Task<byte[]> ReceiveExactTaskAsync(this Socket socket, int len)
{
byte[] buf = new byte[len];
int totalRead = 0;
do{
int read = await ReceiveTaskAsync(socket, buf, totalRead, buf.Length - totalRead);
if (read <= 0) throw new SocketException();
totalRead += read;
}while (totalRead != buf.Length);
return buf;
}
public static Task ConnectTaskAsync(this Socket socket, string host, int port)
{
return Task.Factory.FromAsync(
socket.BeginConnect(host, port, null, null),
socket.EndConnect);
}
public static Task SendTaskAsync(this Socket socket, byte[] buffer)
{
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, socket),
socket.EndSend);
}
}
static void Main()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.ConnectTaskAsync("127.0.0.1", 443);
var buf1 = s.ReceiveExactTaskAsync(100); //read exactly 100 bytes
Console.Write(Encoding.UTF8.GetString(buf1.Result));
var buf2 = s.ReceiveExactTaskAsync(100); //read exactly 100 bytes
Console.Write(Encoding.UTF8.GetString(buf2.Result));
Console.ReadLine();
}
Sender Code :
// use same extension method class like above ....^
void Main()
{
Socket s = new Socket(SocketType.Stream , ProtocolType.Tcp);
s.ConnectTaskAsync( "127.0.0.1" , 443);
s.SendTaskAsync(Encoding.UTF8.GetBytes("hello"));
s.Close();
Console.ReadLine();
}
notice I removed the async from main since im testing it in console.
Question ,
According to link above , the code should work
However I'm getting no exception and it's just hangs on that line :
Console.Write(Encoding.UTF8.GetString(buf1.Result));
(First I run receiver , then I run sender)
What am I missing?
the problem comes from the "notice I removed the async from main since im testing it in console.".
You need to wait for the operation to complete before doing the next step. The code you used as an example pauses at each await for the operation to complete, your code just goes straight through.
You may be able to fix this by putting a .Wait() after each operation that would have had a await or by running this function inside a threadpool thread via Task.Run(, however I think it is better to know when you should use async and when you should not.
Async should be used when you have other work you could have the thread be doing, very commonly that "other work" will be things like processing UI messages on a WinForms project or accepting new connections on a ASP.NET site. In a console application there is no other work your program could be doing while it waits, so in that situation it would be more appropriate to use the synchronous version of the functions instead.
P.S. You made the comment after I posted "that's why I remove the async awaits and used Task.result", just so you know never ever1 combine code that uses await and code that blocks the synchronization contest (by using things like Task.Result or Task.Wait(), you will likely cause your code to deadlock and stop functioning!
It is not a issue for your current example because console applications do not have a synchronization context, but if you copied and pasted this code to something that did you could easily lock up your program.
1: Ok, you could combine await and blocking code but there are rules you need to follow, but if you know enough to dispute my what I am saying you know enough to safely do it. If you don't know how to safely do it just avoid doing it
since you do not wait for the threads to do their work and then call s.Close() the socket will be closed before any traffic is sent out.
You would have to either remove the s.Close() call or wait until the calls are complete, for instance via
Task connect = s.ConnectTaskAsync( "127.0.0.1" , 443);
connect.Wait(); // you have to connect before trying to send
Task sendData = s.SendTaskAsync(Encoding.UTF8.GetBytes("hello"));
sendData.Wait(); // wait for the data to be sent before calling s.Close()
s.Close();
or you could box it in a method and Wait for that method to complete. The end result is to not call Close before completing the previous calls.
void Main()
{
Socket s = new Socket(SocketType.Stream , ProtocolType.Tcp);
Task worker = DoWorkAsync(s);
worker.Wait();
s.Close();
Console.ReadLine();
}
private async Task DoWorkAsync(Socket s){
await s.ConnectTaskAsync( "127.0.0.1" , 443);
await s.SendTaskAsync(Encoding.UTF8.GetBytes("hello"));
}

Is this an async reading?

I have a listen() function which is reading the networkstream and a callback function newDataRecievedCallback.
I call a method BeginRead which is Async, but I call the same method in the callback function again. Isn't it then sync logic?
Is there anotherway to do it?
private void listen()
{
networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
}
private void newDataRecievedCallback(IAsyncResult rst)
{
try
{
int recievedDataSize = tcpClient.Client.Receive(buffer);
recievedData = convertToString(buffer, incomeDataSize);
//End Read
networkStream.EndRead(rst);
cleanBuffer();
parseXMLData(recievedData);
//Hier I call the same async method
networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
If BeginRead always completes asynchronously then calling it again in the callback will still be asynchronous.
However BeginRead will sometimes complete synchronously (check IAsyncResult.CompletedSynchronously), thus your code is vulnerable to stack overflows when you get unlucky. For example, this could happen in one thread: newDataRecievedCallback -> BeginRead -> newDataRecievedCallback -> BeginRead and so on.
The proper way to use BeginRead is to use a pattern similar to the one below (this is a code snippet from C# 4.0 in a Nutshell). In essence, you should always check if the method completed synchronously and then act appropriately.
void Read() // Read in a nonblocking fashion.
{
while (true)
{
IAsyncResult r = _stream.BeginRead
(_data, _bytesRead, _data.Length - _bytesRead, ReadCallback, null);
// This will nearly always return in the next line:
if (!r.CompletedSynchronously) return; // Handled by callback
if (!EndRead (r)) break;
}
Write();
}
void ReadCallback (IAsyncResult r)
{
try
{
if (r.CompletedSynchronously) return;
if (EndRead (r))
{
Read(); // More data to read!
return;
}
Write();
}
catch (Exception ex) { ProcessException (ex); }
}
bool EndRead (IAsyncResult r) // Returns false if there’s no more data
{
int chunkSize = _stream.EndRead (r);
_bytesRead += chunkSize;
return chunkSize > 0 && _bytesRead < _data.Length; // More to read
}
It is still asynch because your call to networkStream.BeginRead does not block. You make the call and then exit the function. Yes, it will be called again but still in an asynch manner.
Is there another way? Yes, hundreds of ways. Your code isn't bad. It just seems a bit tightly coupled in that your asynch handler is performing its own management as well as processing data. A cleaner way would be to have some sort of controller which your newDataRecievedCallback would notify via a delegate, and pass the data to it for processing. The controller would also be responsible for spawning the next asynch process. A separate controller could also pass the received data for processing without blocking more asynch calls.

C#: How to set AsyncWaitHandle in Compact Framework?

I'm using a TcpClient in one of my Compact Framework 2.0 applications. I want to receive some information from a TCP server.
As the Compact Framework does not support the timeout mechanisms of the "large" framework, I'm trying to implement my own timeout-thing. Basically, I want to do the following:
IAsyncResult result = networkStream.BeginRead(buffer, 0, size, ..., networkStream);
if (!result.AsyncWaitHandle.WaitOne(5000, false))
// Handle timeout
private void ReceiveFinished(IAsyncResult ar)
{
NetworkStream stream = (NetworkStream)ar.AsyncState;
int numBytes = stream.EndRead(ar);
// SIGNAL IASYNCRESULT.ASYNCWAITHANDLE HERE ... HOW??
}
I'd like to call Set for the IAsyncResult.AsyncWaitHandle, but it doesn't have such a method and I don't know which implementation to cast it to.
How do I set the wait handle? Or is it automatically set by calling EndRead? The documentation suggests that I'd have to call Set myself...
Thanks for any help!
UPDATE
Seems that the wait handle is set automatically when calling EndRead - but it's not in the docs. Can somebody confirm this?
UPDATE 2
Wrote client.BeginRead in my sample code. Of course, BeginRead is called on the NetworkStream...
I think you have a misunderstanding about async IO with TCP.
To kick off async IO, call stream.BeginRead().
In the callback, you call EndRead on the stream.
You don't call BeginRead on the TcpClient, as your code shows. Your app doesn't ever signal the WaitHandle. The IO layer will invoke your callback when the waithandle is signalled, in other words when the async Read happens.
In your callback, normally you'd call BeginRead again, on the stream, if it's possible that you'll be receiving more data.
You can see a clear example in this answer.
Before starting the BeginRead/EndRead dance,
you may want to do an async Connect on the TcpClient - then you would use BeginConnect. But that's done just once. Alternatively, you might want a synchronous connect, in which case you just call TcpClient.Connect().
example code:
private class AsyncState
{
public NetworkStream ns;
public ManualResetEvent e;
public byte[] b;
}
public void Run()
{
NetworkStream networkStream = ...;
byte[] buffer = new byte[1024];
var completedEvent = new ManualResetEvent(false);
networkStream.BeginRead(buffer, 0, buffer.Length,
AsyncRead,
new AsyncState
{
b = buffer,
ns = networkStream,
e = completedEvent
});
// do other stuff here. ...
// finally, wait for the reading to complete
completedEvent.WaitOne();
}
private void AsyncRead(IAsyncResult ar)
{
AsyncState state = ar as AsyncState;
int n = state.ns.EndRead(ar);
if (n == 0)
{
// signal completion
state.e.Set();
return;
}
// state.buffer now contains the bytes read
// do something with it here...
// for example, dump it into a filesystem file.
// read again
state.ns.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
}

Categories

Resources