Search code examples
c#.net-coretcptcpclient

How to set a correct buffer size for TCP message responses


This is how I currently send data to an external TCP server

byte[] data = new byte[0] /* the data to send */;

TcpClient client = new TcpClient("127.0.0.1", 3000); // connect to the tcp server
NetworkStream stream = client.GetStream();
await stream.WriteAsync(data, 0, data.Length);

data = new byte[256]; // set the buffer size
int responseBytes = await stream.ReadAsync(data, 0, data.Length); // store the response to the buffer
string responseData = System.Text.Encoding.ASCII.GetString(data, 0, responseBytes);

stream.Close();
client.Close();

For the response I have to setup the buffer size here new byte[256]. But what if the response is greater than this size? I can't determine the correct size because I'm just connecting to his external server, send a message to it and expect a response. Is there a way I can make this dynamic?


As a sidenote: I'm sending various HL7 messages to clinic servers and they will send back HL7 ACK messages as a response. This gives some information about HL7 ACK messages

https://healthstandards.com/blog/2007/02/01/ack-message-original-mode-acknowledgement/

An example ACK could be

MSH|^~&|CATH|StJohn|AcmeHIS|StJohn|20061019172719||ACK^O01|MSGID12349876|P|2.3 MSA|AA|MSGID12349876


Solution

  • For the response I have to setup the buffer size here new byte[256]. But what if the response is greater than this size?

    Then you call stream.ReadAsync() and append your buffer (or the decoded string) to a larger buffer until you know you have received the entire message, which you need to do anyway: the Write() from one end of the socket does not need to correspond to one Read() on the other end. Multiple writes can be read in a single read, or the other way around.

    So something like this:

    data = new byte[256]; // set the buffer size
    var builder = new StringBuilder();
    
    do
    {
        int responseBytes = await stream.ReadAsync(data, 0, data.Length); // store the response to the buffer
        string responseData = System.Text.Encoding.ASCII.GetString(data, 0, responseBytes);
        builder.Append(responseData);
    } while (responseBytes > 0)
    

    Do note that this happens to work with ASCII, as it doesn't have multibyte characters. Were it UTF-8 or a similar encoding, the 256th byte could be the start of a character which continues into the next read, i.e. byte 1 (and perhaps 2) of the next read.

    This code also assumes you want to keep reading until the connection is closed (then responseBytes = 0). If this protocol has a length prefix or message terminator, you have to handle those.

    Usually you don't want to implement this low-level stuff yourself, aren't there libraries available that handle the HL7 protocol?