Как передавать "разношерстные" данные по TCP?
Мне нужно использовать TCP протокол. От сервера могут поступить два вида данных: команда (начинается со знака '/', далее имя и доп данные), либо целый файл. Читаю данные от сервера таким образом:
public byte[] GetData(TcpClient client)
{
NetworkStream stream = client.GetStream();
byte[] fileSizeBytes = new byte[4];
int bytes = stream.Read(fileSizeBytes, 0, 4);
int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
int bufferSize = 1024;
int bytesRead = 0;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
if (client.Available < curDataSize)
curDataSize = client.Available;
bytes = stream.Read(data, bytesRead, curDataSize);
bytesRead += curDataSize;
bytesLeft -= curDataSize;
}
return data;
}
Мне кажется немного не правильным решением, преобразовывать каждый раз все к строке и проверять, содержит ли она команду. В идеале, я бы хотел иметь две разные функции чтения (под строку и под целый файл). Также, есть идея, отвести первые несколько байт (допустим 8) под 'тип' информации, читать их сначала и уже после решать как обрабатывать дальнейшие байты. Возможно я изобретаю велосипед и есть более простое решение?
Ответы (1 шт):
TCP клиент-сервер как реализовать передачу данных без краша сервера?
В этом примере в заголовек передается только длина пакета. Но рядом с ней можно передавать тип пакета. В зависимости от типа вызывать требуемый обрабочик полученных данных.
public enum MessageType : byte
{
Text = 0,
File = 1
}
class MessageHeader
{
public MessageType Type { get; }
public int Length { get; }
public MessageHeader(MessageType type, int length)
{
Type = type;
Length = length;
}
public byte[] ToArray()
{
byte[] result = new byte[5];
result[0] = (byte)Type;
BinaryPrimitives.WriteInt32LittleEndian(result.AsApan()[1..], Length);
return result;
}
public static MessageHeader FromArray(ReadOnlySpan<byte> buffer)
{
return new MessageHeader((MessageType)buffer[0], BinaryPrimitives.ReadInt32LittleEndian(buffer[1..]));
}
}
Использовать это можно как-то так.
MessageHeader header = MessageHeader.FromArray(bytes);
switch (header.Type)
{
case MessageType.Text:
// ...
break;
case MessageType.File:
// ...
break;
}
MessageHeader header = new MessageHeader(MessageType.File, 12345);
byte[] headerBytes = header.ToArray();