Communication with the server via async / wait?

I want to create sending a Socket message through TAP via async / wait.

After reading this answer and this, I decided to create a fully working sample:

So what I tried:

I took the TAP extension methods from here (everything is fine): and I am testing it in the cmd console:

Recipient 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(); } 

Sorry, I removed async from main, since im tested it in the console.

Question,

According to the link above, the code should work

However, I am not getting an exception, and it just hangs on this line:

Console.Write(Encoding.UTF8.GetString(buf1.Result));

(First I start the receiver, then I start the sender)

What am I missing?

+1
source share
2 answers

The problem is due to the "notification that I removed async from main, since I tested it on the console."

You need to wait for the operation to complete before taking the next step. The code you used as an example stops at each await to complete the operation, your code just goes right through.

Perhaps you can fix this by putting .Wait() after every operation that would have await , or by running this function inside threadpool thread via Task.Run( however I think it's better to know when you should use async and when no.

Async should be used when you have another job that you could do a thread in , very often that the โ€œother jobโ€ would be things like handling user interface messages in a WinForms project or accepting new connections to an ASP.NET site . There is no other work in the console application that your program could do while it waits, so in this situation it would be more appropriate to use the synchronous version of the functions.


PS You made a comment after I sent the message โ€œwhy I delete the asynchronous wait and used Task.resultโ€, so you never know that 1 combines code that uses await and code that blocks the synchronization contest (using such things , like Task.Result or Task.Wait() , you will probably make your code slow down and stop functioning!

This is not a problem for your current example, because console applications do not have a synchronization context, but if you copied and pasted this code into something, you could easily lock your program.

1: Well, you could combine await and blocking code, but there are rules that you need to follow, but if you know enough to dispute what I'm saying, you know enough to safely do this. If you do not know how to do it safely, just avoid it.

+4
source

since you do not wait for the threads to do their work, and then call s.Close() , the socket will be closed until any traffic is sent. You will either have to delete the s.Close() call, or wait for the call to complete, for example, through

  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 can set it in a method and wait for the completion of this method. The end result is not calling Close before making 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")); } 
+1
source

Source: https://habr.com/ru/post/1486071/


All Articles