C# list vs byte array efficiency over network - c#

Okay so I'm trying to make a multiplayer game using a self built netcode in unity3d using c#,
The thing is since I'm using raw tcp I need to convert everything to a byte[] but I got sick of using Array.Copy. Since I'm reserving a few bytes of every message sent over a network as sort of a message identifier that I can use to interpret the data I receive.
So my question is, for the purpose of making this code more friendly to myself, is it a terrible idea to use a list of bytes instead of a byte array and once I've prepared the message to be sent I can just call .ToArray on that list?
Would this be terrible for performance?

As a general rule when dealing with sockets: you should usually be working with oversized arrays (ArrayPool<byte>.Shared can be useful here), and then use the Send overloads that accepts either the byte[], int, int (offset+count), or ArraySegment<byte> - so you aren't constantly re-copying things, and can re-use buffers. However, frankly: you may also way to look into "pipelines"; this is the new IO API that Kestrel uses that deals with all the buffer management for you, so you don't have to. In the core framework, pipelines is currently mostly server-focused, but this is being improved hopefully in .NET 5 as part of "Bedrock" - however, client-side pipelines wrappers are available in Pipelines.Sockets.Unofficial (on NuGet).
To be explicit: no, constantly calling ToArray() on a List<byte> is not a good way of making buffers more convenient; that will probably work, but could contribute to GC stalls, plus it is unnecessary overhead in your socket code.

Related

Can I make HTTP requests using OpenCL in C#?

Can I make HTTP requests using OpenCL in C#? I tryed to do this calling system("curl website.com") but only getting an error about system implicit calling.
No, you can't. The OpenCL kernel C/C++ language doesn't support the standard C library - this library is replaced by a custom set of standard functions, geared toward math programming.
The list of functions, which can be used in the kernel language, can be found here.
As others have said, no, it's not possible to do I/O in OpenCL kernels.
Moreover though, it makes no sense to do so; OpenCL is specialised on computationally-intensive massively parallel data processing. Waiting for I/O to complete would entirely defeat the point of it. The usual pattern is:
Collect and prepare your data in the host environment (regular CPU based programming environment; sounds like C# in your case although that's not entirely clear?)
Create OpenCL buffers and fill them with the data
Perform computation in kernels
Put results in buffers
Read back results from the buffers on the host.
Further processing of results, e.g. writing to disk, network, or display on the host.

TcpClient performance - sending 4 scalar values much slower than sending 1 byte array containing all values

I'm writing an application where two applications (say server and client) are communicating via a TCP-based connection on localhost.
The code is fairly performance critical, so I'm trying to optimize as best as possible.
The code below is from the server application. To send messages, my naive approach was to create a BinaryWriter from the TcpClient's stream, and write each value of the message via the BinaryWriter.
So let's say the message consists of 4 values; a long, followed by a bolean value, and then 2 more longs; the naive approach was:
TcpClient client = ...;
var writer = new BinaryWriter(client.GetStream());
// The following takes ca. 0.55ms:
writer.Write((long)123);
writer.Write(true);
writer.Write((long)456);
writer.Write((long)2);
With 0.55ms execution time, this strikes me as fairly slow.
Then, I've tried the following instead:
TcpClient client = ...;
// The following takes ca. 0.15ms:
var b1 = BitConverter.GetBytes((long)123);
var b2 = BitConverter.GetBytes(true);
var b3 = BitConverter.GetBytes((long)456);
var b4 = BitConverter.GetBytes((long)2);
var result = new byte[b1.Length + b2.Length + b3.Length + b4.Length];
Array.Copy(b1, 0, result, 0, b1.Length);
Array.Copy(b2, 0, result, b1.Length, b2.Length);
Array.Copy(b3, 0, result, b1.Length + b2.Length, b3.Length);
Array.Copy(b4, 0, result, b1.Length + b2.Length + b3.Length, b4.Length);
client.GetStream().Write(result, 0, result.Length);
The latter runs in ca 0.15ms, while the first approach took roughly 0.55ms, so 3-4 times slower.
I'm wondering ... why?
And more importantly, what would be the best way to write messages as fast as possible (while maintaining at least a minimum of code readability)?
The only way I could think of right now is to create a custom class similar to BinaryWriter;
but instead of writing each value directly to the stream, it would buffer a certain amount of data (say 10,000 bytes or such) and only send it to the stream when its internal buffer is full, or when some .Flush() method is explicitly called (e.g. when message is done being written).
This should work, but I wonder if I'm overcomplicating things and there's an even simpler way to achieve good performance?
And if this was indeed the best way - any suggestions how big the internal buffer should ideally be? Does it make sense to align this with Winsock's send and receive buffers, or best to make it as big as possible (or rather as big as sensible given memory constraints)?
Thanks!
The first code does four blocking network-IO operations, while the second one does only one. Usually, most types of IO operations incur in quite heavy overhead, so you would presumably want to avoid small writes/reads and batch things up.
You should always serialize your data, and if posible, batch it into a single message. This way you would avoid as much IO overhead as possible.
Probably the question is more about Interprocess Communication (IPC) rather than TCP protocol. There are multiple options to use for IPC (see Interprocess Communications page on Microsoft Dev Center). First you need to define your system requirements (how the system should perform/scale), than you need to choose a simplest option that works best in your particular scenario using performance metrics.
Relevant excerpt from Performance Culture article by Joe Duffy:
Decent engineers intuit. Good engineers measure. Great engineers do both.
Measure what, though?
I put metrics into two distinct categories:
Consumption metrics. These directly measure the resources consumed by running a test.
Observational metrics. These measure the outcome of running a test, observationally, using metrics “outside” of the system.
Examples of consumption metrics are hardware performance counters, such as instructions retired, data cache misses, instruction cache misses, TLB misses, and/or context switches. Software performance counters are also good candidates, like number of I/Os, memory allocated (and collected), interrupts, and/or number of syscalls. Examples of observational metrics include elapsed time and cost of running the test as billed by your cloud provider. Both are clearly important for different reasons.
As for TCP, I don't see the point of writing data in small pieces when you can write it at once. You can use BufferedStream to decorate TCP client stream instance and use same BinaryWriter with it. Just make sure you don't mix reads and writes in a way that forces BufferedStream to try to write internal buffer back to the stream, because that operation is not supported in NetworkStream. See Is it better to send 1 large chunk or lots of small ones when using TCP? and Why would BufferedStream.Write throw “This stream does not support seek operations”? discussions on StackOverflow.
For more information check Example of Named Pipes, C# Sockets vs Pipes, IPC Mechanisms in C# - Usage and Best Practices, When to use .NET BufferedStream class? and When is optimisation premature? discussions on StackOverflow.

Memory-efficient IList<T> implementation

I need a collection type for received bytes in my socket application (which deals with ~5k of concurrent connections).
I tried using a List<byte> but since it has one internal array and I receive lots of data, it can cause OutOfMemoryExceptions.
So I need a collection that,
Keeps the data in smaller blocks; like an Unrolled Linked List.
Provides fast lookup (Preferably an IList<T>) because I look for a delimiter that marks the end of the message after each receive operation.
What I use right now is Stream. I supply a MemoryStream for the operations that don't involve too much data and supply a FileStream of a temporary file for the operations that involve serious amounts of data.
MemoryStream is no different than a List<T>, though and I prefer not to use files as buffers.
So...
What collection or approach do you recommend?
It appears that you are using inappropriate architecture for a network application. You should buffer only those data which is required. Here you are using a list to buffer the data until the required amount of data is received.
I would recommend that you should check for delimiter on each receipt of data in the data itself and if it is there, you should push in only the data till you encounter the delimiter. Once the data is ready, you should fetch it out from list and use it and dispose off the list. Adding up everything to the list is not a good approach and will surely consume a lot of memory.
Ideally, you should have a protocol which always inform you before you actually receive the data about the length of data you are going to receive. This way, you can be sure that required data has been received and you should not rely on the delimiter.
A possible quick and dirty solution:
At the start of the program, allocate a buffer large enough for the largest amount of data you will receive. Use a separate 'count' field to keep track of how much data is currently in use.
(I don't really like this solution; I'd use files or find some way of working with the data in blocks, but it might work for you).

What is the difference between Socket.Send and Stream.Write? (in relation to tcp ip connections)

In dealing with server/client connections, I have seen both of these used effectively without any apparent advantages to either, yet I doubt they would both exist if there weren't any known advantages to one or the other. Does anyone know any clear differences between the two? Help would be much appreciated, thanks.
Socket.Send is a raw send of data directly through the WINSOCK layer... Stream buffers and processes data as you send it. It's generally used for situations where you need stream-like functionality. There's some extra overhead there, obviously. In comparison to Send, this overhead includes creating a new class to manage a "stream" and introducing a couple of layers of indirection between you and Socket.Send. NetworkStream.Write eventually just calls Socket.Send; but that's a couple of layers of overhead down.
There's also a bit more work to get the stream set up, through the use of the NetworkStream type.
If course, a stream can also be bidirectional, meaning you can both read and write to it. You can read from a socket perfectly fine with the Receive methods.
Use of Send or Receive directly couples you to socket. If you use a Stream-derivative, you're decoupled from Socket and free to use methods/classes that work with Stream.

Need C# client to connect to server with low latency bi-direction communication

I'm in the process of learning C# and just need a pointing in the right direction. I want to build a client in C# that communicates with a server running PHP/mySQL. There will need to be almost constant communication between the two. It will be for a game, so low-latency and bi-directional communication. I'm not looking for an exact how-to, but rather what method I need to use to connect the two for the fastest and most reliable connection. I have read others use XML, but that seems like it would be slower if used near-constantly, like once or more a second, but I could be totally wrong. Thanks in advance!
Normally communication with those characteristics is made over a persistent TCP connection. C# offers lots of ready-to-use functionality in the System.Net.Sockets namespace (start looking from TcpClient and TcpListener; there are also more low-level interfaces if you need them).
The important question here is: what do you mean exactly "server running PHP"? If the server offers only an HTTP interface, then you would find it more natural to communicate not with sockets but with the WebClient or the more low-level HttpWebRequest classes instead.
Ah, writing a game in C# as a means to get started with the language! How many have started this way.
Have you defined your client-server protocol yet? I'm not talking about TCP vs. UDP, which TomTom and Jon have discussed. I mean, what is the data stream going to look like?
Packet fragmentation is the enemy of low-latency network code. Learn about MTU and packet fragmentation, Nagle's algorithm, etc. and write down some notes for later when you implement the network code. Make sure you calculate the smallest size packet you would be interested in sending, how big its headers might be, and how large of a payload you can fit into that packet. Then see if you can come up with a protocol that uses the available space efficiently.
You may gain a lot more by optimizing your server application and/or porting it to a different language. Just because you CAN use PHP for everything server side doesn't mean you SHOULD. Keep the part that shows you useful information in a web browser, and evaluate whether you should rewrite the time-critical and game client communication parts in another language. Interpreted languages are not especially well known for their speed when crunching real-time game world data. Sure, I once wrote something like that in Perl using POE, but ultimately it was a lot less performant than the C code I was mimicking.
Finally, I would recommend you look into XNA, since it has a lot of this stuff already.

Categories