Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Sending sf::Packet via asio fails partly  (Read 11229 times)

0 Members and 1 Guest are viewing this topic.

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Sending sf::Packet via asio fails partly
« on: September 09, 2021, 09:16:27 pm »
I programmed a pong multiplayer game using SFML, where i used sf::UdpSockets for transferring data between two PCs. It worked great. Next i wanted to check out how the result would look like if i used the asio network library for networking instead of the SFML Network-classes.

Here my first big issue was, that asio does not provide a class similar to sf::Packet that helps with serializing the data.
With SFML its so beautifully simple, for example if you want to store an enum and some data that belongs to the enum, you could just do:
enum class CommandsToServer{
        Connect, // empty
        Disconnect, // empty
        Data // Vector2f
};
...

sf::Packet packet;
packet << static_cast<uint8_t>(CommandsToServer::Data);
packet << x << y;

and send the packet to the server, where you unpack the content the same way you put it in.
uint8_t command;
uint8_t x, y;
// ... receive packet from socket ...
receivedPacket >> command >> x >> y;
CommandToServer commandToServer = static_cast<CommandToServer>(command);
 

Since i did not find a straightforward way to pack different types into an array, i just used sf::Packet again with the asio::ip::udp::socket.

This approach looks like this:
    m_packet << static_cast<uint8_t>(5);
    m_packet << static_cast<uint8_t>(6);
    m_socket.send_to(asio::buffer(m_packet.getData(), m_packet.getDataSize()), m_serverEndpoint);


So i just try to transfer two values over the network: 5 and 6.

On the server-side i use

std::array<char, 256> m_receiveBuffer;
...
// in some function
    m_socket.async_receive_from(
            asio::buffer(m_receiveBuffer), m_remoteEndpoint,
            std::bind(&Server::handle_receive, this,
                      std::placeholders::_1,
                      std::placeholders::_2));
 ...

void Server::handle_receive(const asio::error_code &error, std::size_t l_receivedBytes) {
    sf::Packet packet;
    std::cout << "received bytes: " << int(l_receivedBytes) << "\n"; // Output: received bytes 2
    packet.append(m_receiveBuffer.data(), l_receivedBytes);
    int num1; int num2;
    packet >> num1 >> num2;
    std::cout << num1 << ", " << num2 << ".\n"; // Output: 0, 0
    receiveData();
 
Console prints 0, 0. But if i start the debugger and set a breakpoint at the last std::cout-statement, i can see that
packet has the following members:
m_data
[ 0 ] = {char}5 '\005'
[ 1 ] = {char}6 '\006’
m_readPos = 0
m_sendPos = 0
m_isValid = false

Its strange because the values 5 and 6 have apparently been transferred successfully, since they are stored in the std::vector<char> container of sf::Packet. However, they don't get transferred via the >> operator into the variables num1 and num2. I don't know the reason why i cannot transfer the data out of the sf::Packet into the variables on the server-side.
« Last Edit: September 10, 2021, 10:36:06 am by Grundkurs »

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Re: Sending sf::Packet via asio fails partly
« Reply #1 on: September 10, 2021, 10:43:41 am »
i found out that the checkSize() method from

// SFML Packet.cpp
Packet& Packet::operator >>(Int32& data)
{
    if (checkSize(sizeof(data)))
    {
        std::memcpy(&data, &m_data[m_readPos], sizeof(data));
        data = ntohl(data);
        m_readPos += sizeof(data);
    }

    return *this;
}
returns false, thus the data does not get copied into the Int32& data parameter. But i don't know why the check fails.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Sending sf::Packet via asio fails partly
« Reply #2 on: September 10, 2021, 12:21:58 pm »
Hard to say without properly testing it myself.

Two things I see is that you're writing uint8_t but reading int, those might yield different results if not undefined behavior.
Is your ASIO buffer initialized correctly?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sending sf::Packet via asio fails partly
« Reply #3 on: September 10, 2021, 12:36:51 pm »
Your packet contains 2 bytes, but you're trying to read 4 (sizeof(int)). That's what the checkSize function checks, and why it fails.

If you write two uint8_t then read two uint8_t.
Laurent Gomila - SFML developer

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Re: Sending sf::Packet via asio fails partly
« Reply #4 on: September 10, 2021, 11:37:43 pm »
Thank you for the replies! Laurents answer got me on the right track.
I changed the function to
void Server::handle_receive(const asio::error_code &error, std::size_t l_receivedBytes) {
    sf::Packet packet;
    std::cout << "received bytes: " << int(l_receivedBytes) << "\n";
    packet.append(m_receiveBuffer.data(), l_receivedBytes);
    uint8_t num1; uint8_t num2;
    packet >> num1 >> num2;
    std::cout << int(num1) << ", " << int(num2) << ".\n"; // Output: 5, 6
    receiveData();
}

and now the console prints the right values. One of the reasons i got it wrong at first was that i initially even tried using
uint8_t num1
instead of
int num1
but printing uint_t to the console resulted  in strange symbols displayed in the console instead of the numerical values, therefore i wrongly assumed that i produced an error using uint8_t and switched to int, which at least printed some numerical values to the console. My bad. 

However, every time i use some other library (like asio) it reminds me about how well designed SFML is and how effectively it is in hiding the confusing low-level stuff, while still allowing to mix it with low-level libs, if needed.
« Last Edit: September 11, 2021, 12:29:30 am by Grundkurs »