High performance asynchronous pending sockets

I am writing an application that will require hundreds of socket connections via tcp to read / write data.

I met this piece of code here , and I wonder how I can make it more reliable.

I am currently invoking the code:

foreach (var ip in listofIps) { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), 4001); Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.Connect(remoteEP); await ReadAsync(client); } 
  • Is there something wrong with what is described above, and how can it be optimized so that it runs at the same time?

    In the code snippet, the buffer size is set to 1000. As a simple illustration, if I try to print only the received bytes and not the remaining 0x00, I should do something like this:

     while (true) { await s.ReceiveAsync(awaitable); int bytesRead = args.BytesTransferred; if (bytesRead <= 0) break; var hex = new StringBuilder(bytesRead * 2); var msg = new byte[bytesRead]; for (int i = 0; i < bytesRead; i++) msg[i] = args.Buffer[i]; foreach (byte b in msg) hex.AppendFormat("{0:x2} ", b); AppendLog(string.Format("RX: {0}", hex)); } 
  • Is there a more efficient way to do this? I used to iterate over the entire buffer and print out the data, but this will give me a whole chain of trailing 0x00, since my protocol has a length of 60 to 70 bytes.

+4
source share
1 answer

I am writing an application that will require hundreds of socket connections via tcp to read / write data.

You do not need "high performance sockets" for this. The code is much simpler with normal performance sockets.

First, do not use custom expectations from the link you provided. They are great for some people (and completely "reliable"), but you don’t need them, and your code will be easier without them.

  • Is there something wrong with this, and is it possible to optimize it?

Yes. You should not mix lock ( Connect ) and asynchronous ( ReadAsync ) code. I would recommend something like this:

 foreach (var ip in listofIps) { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), 4001); Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await client.ConnectTaskAsync(remoteEP); ... } 

Where ConnectTaskAsync is the standard TAP on top of the APM shell :

 public static Task ConnectTaskAsync(this Socket socket, EndPoint endpoint) { return TaskFactory.FromAsync(socket.BeginConnect, socket.EndConnect, endpoint, null); } 

As Mark Gravell noted, this code (and your source code) connects the sockets one at a time. You can use Task.WhenAll to connect all of them at once.

2) Is there a more efficient way to do this?

First, you must define a TAP-over-APM ReceiveTaskAsync similar to the one described above. When working with binary data, I also like to have an extension method in byte arrays to reset:

 public string DumpHex(this ArraySegment<byte> data) { return string.Join(" ", data.Select(b => b.ToString("X2"))); } 

Then you might have this code:

 while (true) { int bytesRead = await socket.ReceiveTaskAsync(buffer); if (bytesRead == 0) break; var data = new ArraySegment<byte>(buffer, 0, bytesRead); AppendLog("RX: " + data.HexDump()); ... } 

If you do a lot of binary manipulations, you can find my ArraySegments library .

3) Where and how to enable logic to check if all my data got into one read

Oh, this is harder than that. :) Sockets are an abstraction of a stream, not an abstraction of a message. Therefore, if you want to define β€œmessages” in your protocol, you need to specify a length prefix or byte separator so that you can detect message boundaries. Then you need to write code that will analyze your messages, bearing in mind that the data blocks read from the socket can contain only a partial message (so you need to buffer it), a full message, several full messages, and can also complete a partial message (again, buffering). And you should also consider your existing buffer when receiving a new block.

I have Frequently Asked Questions TCP / IP.NET Sockets in my blog, which addresses exactly this question and has some sample code using my personal default setting for generating messages (byte length prefix is ​​4 bytes long).

4) How to enable the writeasync method so that I can send data through a socket in the middle of reading.

This is surprisingly complicated:

 public static Task<int> SendTaskAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags) { return Task<int>.Factory.FromAsync(socket.BeginSend, socket.EndSend, buffer, offset, size, flags, null); } public static Task WriteAsync(this Socket socket, byte[] buffer) { int bytesSent = 0; while (bytesSent != buffer.Length) { bytesSent += await socket.SendTaskAsync(data, bytesSent, buffer.Length - bytesSent, SocketFlags.None); } } 
+17
source

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


All Articles