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

Author Topic: Packets Arrive In Different Order When Non-Blocking Than When Blocking  (Read 2106 times)

0 Members and 2 Guests are viewing this topic.

Endgame

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Hi there

I've recently been exploring the Network module and I created a simple client/server architecture that I'm hoping to implement in another project. The basic design intention was this:

1. Client Inputs To Computer
2. Input Packet Is Sent To Server
3. Server Receives Input Packet
4. Server Prints Packet Contents
5. Repeat

Fairly straightforward. I'm using UDP currently, though I tried switching to TCP and experienced the same issue I describe below. I've checked and triple checked, and yes, my sockets are properly bound and sending/receiving to/from the proper ip's and ports. There is no problem with the connection.

What the problem is is the fact that the server always prints out the packets one iteration after it is supposed to. For example, my expected output, and the output I receive when I set all sockets to block, is this:



However, I don't want the sockets to block - my program should move on if no input is waiting to be received at a socket. So I set the sockets to non-blocking, and with the exact same set of inputs, my new output is this:




I've gone over my code many times, and the blocking state is definitely the cause. I don't understand why changing the blocking would cause such a malfunction. Could anyone enlighten me?

Thanks in advance!
« Last Edit: April 23, 2014, 06:59:18 am by Endgame »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Can you please provide a complete and minimal example that reproduces the problem?
Laurent Gomila - SFML developer

Endgame

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Here's a sample of the glitch. As it is, it works fine, albeit in a blocking state which I do not want. However, if one changes the variable "blockingState" to false to remove said state, one will see the glitch that is plaguing me.
 

#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <sstream>
#include <iostream>

using namespace std;

const bool blockingState = true; //CHANGE TO FALSE TO TRIGGER GLITCH.

string getContents(sf::Packet &packet)
{
    string returnString;
    while(not packet.endOfPacket())
    {
        string nextWord;
        packet >> nextWord;
        returnString = returnString + nextWord;
    }
    return returnString;
}

struct Server
{
    sf::UdpSocket socket;

    Server(short unsigned int cSocket)
    {
        socket.bind(cSocket);
        socket.setBlocking(blockingState);
    }

    void get()
    {
        sf::Packet dataPacket;
        sf::IpAddress senderIp;
        short unsigned int senderSocket;

        socket.receive(dataPacket, senderIp, senderSocket);

        string packetContents;
        packetContents = getContents(dataPacket);

        cout << "(Server) Heard " << packetContents << endl;
    }

};

struct Client
{
    sf::UdpSocket socket;

    sf::IpAddress serverIp;
    short unsigned int serverSocket;

    Client(short unsigned int cSocket)
    {
        socket.bind(cSocket);
        socket.setBlocking(blockingState);
    }

    void connect(sf::IpAddress sIp, short unsigned int sSocket)
    {
        serverIp = sIp;
        serverSocket = sSocket;
    }

    void send()
    {

        sf::Packet outPacket;
        string indata;

        getline(cin, indata);
        outPacket << indata;
        socket.send(outPacket, serverIp, serverSocket);

    }

};

int main()
{

    Client client(55801);
    Server server(55804);
    client.connect(sf::IpAddress::LocalHost, 55804); //NOTE: Not a call to TCP connect...merely specifies a specific ip and socket to use automatically when calling SFML method "send" on an SFML UDP socket.

    while(true)
    {
        client.send();
        server.get();
    }

    return 0;
}
 
« Last Edit: April 24, 2014, 07:50:17 am by Endgame »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
You should always check the status returned by the send and receive functions. This is even more important in non-blocking mode, since most of the time the returned status will be sf::Socket::NotReady because there's no data available. You must process the packet only if socket.receive returned sf::Socket::Done.
Laurent Gomila - SFML developer

Endgame

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Thanks - I changed it to this:

if(socket.receive(dataPacket, senderIp, senderSocket)!=sf::Socket::NotReady)
        {
            string packetContents;
            packetContents = getContents(dataPacket);

            cout << "(Server) Heard " << packetContents << endl;
        }


It's something I have tried before with ineffective results, but I believe I discovered why I wrote this off as the cause - in my larger program, I made calls to both operator cin>> and std::getline(cin, string) sequentially, without clearing the buffer. Rookie mistake, but I just assumed it was your network module causing the problem. Sorry for the waste of your time!
« Last Edit: April 24, 2014, 08:40:00 am by Endgame »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
You should rather check for Done which means "okay", as there are also other possible errors besides NotReady.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything