Невозможно создать одно и то же TCP-сообщение с помощью C # и C

#c# #c #boost-asio #flatbuffers

#c# #c #boost-asio #плоские буферы

Вопрос:

Я хочу создать такое же сообщение и отправить его с помощью C #, как я делаю это с помощью C , где все работает. Обратите внимание, что у меня есть клиент C #, с которым у меня проблемы, клиент C , где все работает нормально, и сервер C , который должен считывать сообщения как от клиентов C #, так и от C .

Вот как я отправляю сообщение с C :

 void ConnectAuthserverCommand::SendLogin(tcp::socket amp;s, const flatbuffers::FlatBufferBuilder amp;builder) const {

    ClientOpcode opc = CLIENT_LOGIN_REQUEST;
    flatbuffers::FlatBufferBuilder builder2;

    auto email = builder2.CreateString("test@abv.bg");
    auto password = builder2.CreateString("test");
    auto loginRequest = Vibranium::CreateLoginRequest(builder2, email, password);
    builder2.FinishSizePrefixed(loginRequest);
    size_t size2 = builder2.GetSize();
    uint8_t *buf2 = builder2.GetBufferPointer();

    uint8_t *actualBuffer2 = new uint8_t[size2   2];
    actualBuffer2[1] = (opc >> 8);
    actualBuffer2[0] = (opcamp;0xFF);
    memcpy(actualBuffer2   2, buf2, size2);

    boost::asio::write(s, boost::asio::buffer(actualBuffer2,size));
}
  

ClientOpcode заключается в следующем:

 enum ClientOpcode : uint16_t{
    CLIENT_AUTH_CONNECTION                            = 0x001,
    CLIENT_LOGIN_REQUEST                              = 0x002,
    CLIENT_NUM_MSG_TYPES                              = 0x003,
};
  

Я делаю следующее: я получаю ClientOpcode сообщение, которое я хочу поместить перед FlatBuffers сообщением. Итак, я создаю массив uint8_t , который я расширяю ровно на 2 байта (потому что размер uint16_t равен 2 байтам). Затем на сервере я прочитал первые 2 байта, чтобы получить заголовок, и вот как я это делаю:

 void Vibranium::Client::read_header() {
    auto self(shared_from_this());
    _packet.header_buffer.resize(_packet.header_size);
    boost::asio::async_read(socket,
    boost::asio::buffer(_packet.header_buffer.data(), _packet.header_size),
    [this, self](boost::system::error_code ec,std::size_t bytes_transferred)
    {
        if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec))
        {
            Disconnect();
        }
        else
        {
            assert(_packet.header_buffer.size() >= sizeof(_packet.headerCode));
            std::memcpy(amp;_packet.headerCode, amp;_packet.header_buffer[0], sizeof (_packet.headerCode));
            if(_packet.headerCode)
                read_size();
            else
                Logger::Log("UNKNOWN HEADER CODE", Logger::FatalError);

        }
    });
}
  

Пока все хорошо, однако я не могу отправить правильно отформатированное то же сообщение с клиента C #. Обратите внимание, что я отправляю точно такие же данные, взгляните:

 Client authClient = GameObject.Find("Client").GetComponent<AuthClient>().client; // This is how I get Client class instance.
ClientOpcode clientOpcode = ClientOpcode.CLIENT_LOGIN_REQUEST;
var builder = new FlatBuffers.FlatBufferBuilder(1);
var email = builder.CreateString("test@abv.bg");
var password = builder.CreateString("test");
var loginRequest = LoginRequest.CreateLoginRequest(builder, email, password);
builder.FinishSizePrefixed(loginRequest.Value);
authClient.Send(builder, clientOpcode);
  

И вот как я на самом деле добавляю заголовок и отправляю данные на C#:

 public static Byte[] PrependClientOpcode(FlatBufferBuilder byteBuffer, ClientOpcode code)
{
    var originalArray = byteBuffer.SizedByteArray();
    byte[] buffer = new byte[originalArray.Length   2];
    buffer[1] = (byte)((ushort)code / 0x0100);
    buffer[0] = (byte)code;
    Array.Copy(originalArray, 0, buffer, 2, originalArray.Length);
    return buffer;
}

public void Send(FlatBufferBuilder builder, ClientOpcode opcode)
{
    byte[] buffer = builder.SizedByteArray();

    var bufferToSend = PrependClientOpcode(builder, opcode);
    if (bufferToSend.Length > MaxMessageSize)
    {
        Logger.LogError("Client.Send: message too big: "   bufferToSend.Length   ". Limit: "   MaxMessageSize);
        return;
    }


    if (Connected)
    {
        // respect max message size to avoid allocation attacks.
        if (bufferToSend.Length <= MaxMessageSize)
        {
            // add to send queue and return immediately.
            // calling Send here would be blocking (sometimes for long times
            // if other side lags or wire was disconnected)
            sendQueue.Enqueue(bufferToSend);
            
            sendPending.Set(); // interrupt SendThread WaitOne()
        }
    }
    else
    {
        Logger.LogWarning("Client.Send: not connected!");
    }
}
  

ClientOpcode перечисление на C # выглядит следующим образом:

 public enum ClientOpcode : ushort
{
    CLIENT_AUTH_CONNECTION                            = 0x001,
    CLIENT_LOGIN_REQUEST                              = 0x002,
    CLIENT_NUM_MSG_TYPES                              = 0x003,
}
  

Я думаю, что могу использовать ushort в качестве замены uint16_t в C #. Вот почему ClientOpcode является ushort .

Когда я отправляю сообщение, я получаю сообщение об ошибке на клиенте UNKNOWN HEADER CODE . Если вы посмотрите на код сервера C для чтения заголовка, вы увидите, что это сообщение отображается, когда сервер не может прочитать код заголовка. Так или иначе, я не могу правильно разместить ClientOpcode заголовок перед TCP-сообщением, отправленным с клиента C #.

Чтобы выяснить, в чем различия, я установил WireShark на хосте для отслеживания обоих сообщений. Вот они:

Это сообщение от корректно работающего клиента C :

введите описание изображения здесь

И это дамп клиента C #:

введите описание изображения здесь

Как вы можете видеть на втором изображении дампа TCP, длина больше. Сообщение C имеет длину 58 , равную длине сообщения C # 62 . Почему?

Клиент C отправляет данные:

 0200340000000c00000008000c00040008000800000014000000040000000400000074657374000000000b00000074657374406162762e626700
  

Когда клиент C # отправляет:

 0000003a0200340000000c00000008000c00040008000800000014000000040000000400000074657374000000000b00000074657374406162762e626700
  

Клиент C # добавляет к нему сообщение впереди 0000003a . Если я удалю эти сообщения, они должны быть одинаковыми, и все будет работать.

Почему мой клиент C # добавляет эти дополнительные данные впереди и как я могу это исправить?

Комментарии:

1. Есть ли конкретная причина, по которой вы не можете использовать объединение различных кодов операций в схеме плоского буфера? Кажется более чистым, чем префикс типа кода операции вручную.

2. @Botje я хотел бы сначала добиться этого вручную. Что касается объединений FlatBuffer, я не совсем уверен, для чего они служат?

3. Согласно документации flatbuffers, вы должны иметь возможность определить Union Op { AuthConnection, LoginRequest } и посмотреть, какой вариант содержит сообщение.

4. Вы не показали, как вы на самом деле отправляете это сообщение. Подозрительно, что 3a равно 58, что соответствует длине сообщения…

5. Проверьте длину bufferToSend … вероятно, оно не содержит этих дополнительных четырех байтов. Поэтому изучите код, который извлекается из sendQueue очереди, который вы не показали.