Search code examples
c#socketstcpclient

TcpListener server - handle data


I have started my first Socket project and I'm wondering how should I read and send data via
server <=> client

Should I make serialized class, use maximum buffer size and don't keep my mind with bytes, or make it all synchronous, read and send bytes only when needed.

Serialize(part of code):

// TcpDLL
[Serializable]
public class SerializedData {
  public string Message { get; set; }
  public DataTypes Type { get; set; }
  public object Data { get; set; }
}

private void ReadStream() {
  // ...
  stream.BeginRead(buffer, 0, MAX_BUFFER_SIZE, new AsyncCallback(ReadAsync), stream);
  // ...
}

private void ReadAsync() {
  // ...
  var dataInfo = (SerializedData)BinaryFormatter.Deserialize(new MemoryStream(buffer));

  if (dataInfo.Type == DataTypes.Register) {
    var data = (RegisterClass)dataInfo.Data;
  }
  // ...
}

Or make it completely synchronous:

private void ReadStream() {
  int bytes = ReadBytesInt(4); // read size of string Message
  string Message = ReadBytesStr(bytes);
  var Type = (DataTypes)ReadBytesInt(4);
  bytes = ReadBytesInt(4); // read size of Data

  if (Type == DataTypes.Register) {
    RegisterClass.ReadStream();
  }
  // ...
}

private void RegisterClass.ReadStream() {
  int id = ReadBytesInt(4);
  // Read rest of data
}

Or maybe combine it? Something like this:

private void ReadStream() {
  int bytes = ReadBytesInt(4); // read size of SerializedData object
  var dataInfo = (SerializedData)ReadBytesAndDeserialize(bytes);
  // ...
}

What is the best way and why? Is this better to read more data once or make it as small as possible?


Solution

  • TCP is a streaming protocol, so if you want to send more than a single message, you should provide some way to indicate to the other end when a message is completed.

    This is usually done by first sending the size of the message, followed by the message itself. So yes, the combination of what you're doing now is what people usually do.

    However you should keep in mind that data might not be received all in once - TCP only ensures that data is received in the order it was sent, and subsequet. In other words:

    • Keep reading until you have read the size of the incoming message
    • Create a buffer the side of the incoming message
    • Keep reading until the buffer is filled

    The amount of data read is not really relevant, incoming data is stored at the socket level, and your read operation just empties that local buffer. Of course reading byte by byte is not recommended.

    Size matters, and there's no need to specify a size for each separate field. However don't worry about a few bytes extra.