В настоящее время я использую клиент C# для моего сервера C++. Протокол связи двоичный. На стороне сервера нет проблем, поскольку двоичная сериализация - это всего лишь вопрос memcpy. Однако у моего клиента C# есть проблемы с отправкой данных через сокеты.Двоичная сериализация на сокетах
Прежде всего, здесь мои структуры данных:
Заголовок:
[Serializable]
public class Header
{
public UInt32 UserId { get; set; }
public UInt16 CheckSum { get; set; }
public byte Status { get; set; }
public byte Command { get; set; }
public byte Device { get; set; }
public byte Method { get; set; }
public byte KeepAlive { get; set; }
public byte Osef { get; set; }
public Header()
{
UserId = 0;
CheckSum = 0;
Status = 0;
Command = 0;
Device = 0;
Method = 0;
KeepAlive = 0;
Osef = 0;
}
public static UInt16 Size()
{
return Convert.ToUInt16(sizeof(byte) * 6 + sizeof(UInt32) + sizeof(UInt16));
}
internal void write(Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(UserId);
writer.Write(CheckSum);
writer.Write(Status);
writer.Write(Command);
writer.Write(Device);
writer.Write(Method);
writer.Write(KeepAlive);
writer.Write(0); //alignement
}
internal void read(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
UserId = reader.ReadUInt32();
CheckSum = reader.ReadUInt16();
Status = reader.ReadByte();
Command = reader.ReadByte();
Device = reader.ReadByte();
Method = reader.ReadByte();
KeepAlive = reader.ReadByte();
reader.ReadByte(); //alignement
}
}
Структура данных с заголовком первого:
[Serializable]
class UserPass
{
public Header Header { get; set; }
public UInt16 User_checkSum { get; set; }
public byte[] Username { get; set; }
public UInt16 Pass_checkSum { get; set; }
public byte[] Password { get; set; }
public UInt16 Size()
{
return Convert.ToUInt16((sizeof(byte) * 128) + (sizeof(byte) * 128) + sizeof(UInt16) * 2);
}
public UserPass()
{
Header = new Header();
User_checkSum = 0;
Username = new byte[128];
Pass_checkSum = 0;
Password = new byte[128];
}
internal void write(Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
Header.write(stream);
writer.Write(User_checkSum);
writer.Write(Username, 0, 128);
writer.Write(Pass_checkSum);
writer.Write(Password, 0, 128);
}
internal void read(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
Header.read(stream);
User_checkSum = reader.ReadUInt16();
Username = reader.ReadBytes(User_checkSum);
Pass_checkSum = reader.ReadUInt16();
Password = reader.ReadBytes(Pass_checkSum);
}
}
я пишу мои данные, используя записи функции Header и UserPass и передачу NetworkStream в качестве аргумента, который я преобразовал из своего сокета с GetStream.
Проблема в том, что сервер правильно получает заголовок, причем каждое поле содержит значения, инициализированные клиентом, но остальные данные заполняются нулями.
Я попытался использовать тот же объект BinaryWriter для обоих. Не разрешил.
Я пробовал с промывкой струей. Не разрешил (а)
Я пробовал некоторые причудливые библиотеки и библиотеку protobuf-net. Это сделало еще хуже, заголовок был полон тарабарщины.
Что интересно, когда я пытаюсь сериализация этих структур в файл, используя те же методы, что либо библиотека или методы записи структур, он отлично работает, данные, хранящиеся в файле правильный, но когда я отправляю его через сокет, он терпит неудачу.
Ошибка на стороне чтения, пожалуйста, укажите код десериализации C++. –
читая контрольную сумму и рассматривая это как длину, звучит немного ... нечетно; вы уверены, что используете это право? Я должен сказать, однако: я делаю * много * программирования 'Stream' и' Socket'. Количество раз, когда я использую 'BinaryReader' /' BinaryWriter': ноль. Это просто не полезно для большинства протоколов. –
О, и в самом деле: protobuf-net не поможет, если фактический протокол здесь protobuf, что я сомневаюсь. У вас есть определение фактического протокола? –