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

Author Topic: Server and client can't both send and receive at the same time?  (Read 4433 times)

0 Members and 1 Guest are viewing this topic.

zakkor

  • Newbie
  • *
  • Posts: 27
    • View Profile
Server and client can't both send and receive at the same time?
« on: October 24, 2014, 07:35:55 pm »
The code in its current form works, (with the server that ONLY receives data, and the client only SENDING data) but if you uncomment the currently commented blocks (server receives data and sends it back, and the client the same), it doesn't send or receive anything anymore...

#include <iostream>
#include <SFML/Network.hpp>
#include <SFML/Graphics.hpp>
#include <winsock2.h>

using std::cout;
using std::cin;

class Player
{
public:
    Player();

    int x, y;
    sf::RectangleShape shape;
};

Player::Player()
{
    x = y = 0;
    shape.setFillColor(sf::Color::White);
    shape.setSize(sf::Vector2f(50, 100));
}

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
    window.setVerticalSyncEnabled(true);
    bool isServer = false;
    cout << "Server/Client ? 1/0\n";
    cin >> isServer;

    if (!isServer)
    {
        sf::Int32 datax;
        sf::Int32 datay;
        Player player1, player2;
        player2.shape.setFillColor(sf::Color::Red);

        sf::TcpSocket socket;
        sf::Socket::Status status = socket.connect("localhost", 53000);
        if (status != sf::Socket::Done)
        {
            // error...
        }

        while (window.isOpen())
        {
            sf::Event event;
            while (window.pollEvent(event))
            {
                // Close window : exit
                if (event.type == sf::Event::Closed)
                    window.close();
                if (event.type == sf::Event::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::W)
                    {
                        player1.y--;
                    }
                    if (event.key.code == sf::Keyboard::S)
                    {
                        player1.y++;
                    }
                    if (event.key.code == sf::Keyboard::A)
                    {
                        player1.x--;
                    }
                    if (event.key.code == sf::Keyboard::D)
                    {
                        player1.x++;
                    }
                }
            }

            sf::Packet packet2;
//            if (socket.receive(packet2) != sf::Socket::Done)
//            {
//                cout << "Couldn't recieve data from server.\n";
//            }
//            else
//            {
//                cout << "Recieved data from server.\n";
//            }

            sf::Int32 enemydatax, enemydatay;
            packet2 >> enemydatax, enemydatay;
            player2.x = enemydatax;
            player2.y = enemydatay;
            player2.shape.setPosition(player2.x, player2.y);
            player1.shape.setPosition(player1.x, player1.y);
            window.clear(sf::Color::Black);

            window.draw(player2.shape);
            window.draw(player1.shape);
            window.display();

            //Send our clients position to the server
            sf::Packet packet1;
            datax = player1.x;
            datay = player1.y;
            packet1 << datax << datay;

            // TCP socket:
            if (socket.send(packet1) != sf::Socket::Done)
            {
                cout << "Couldn't send data to server.\n";
            }
            else
            {
                cout << "Sent data to server.\n";
            }
        }
    }
    else
    {
        sf::TcpListener listener;
        sf::Int32 datax;
        sf::Int32 datay;
        Player player1, player2;
        player2.shape.setFillColor(sf::Color::Red);

        // bind the listener to a port
        if (listener.listen(53000) != sf::Socket::Done)
        {
            cout << "Error: No connections.\n";
        }

        // accept a new connection
        sf::TcpSocket client;
        if (listener.accept(client) != sf::Socket::Done)
        {
            cout << "error client\n";
        }


        while (window.isOpen())
        {
            sf::Event event;
            while (window.pollEvent(event))
            {
                // Close window : exit
                if (event.type == sf::Event::Closed)
                    window.close();
                if (event.type == sf::Event::KeyPressed)
                {
                    if (event.key.code == sf::Keyboard::W)
                    {
                        player1.y--;
                    }
                    if (event.key.code == sf::Keyboard::S)
                    {
                        player1.y++;
                    }
                    if (event.key.code == sf::Keyboard::A)
                    {
                        player1.x--;
                    }
                    if (event.key.code == sf::Keyboard::D)
                    {
                        player1.x++;
                    }
                }
            }
            sf::Packet packet2;
            if (client.receive(packet2) != sf::Socket::Done)
            {
                cout << "Couldn't recieve data from client.\n";
            }
            else
            {
                cout << "Recieved data from client.\n";
            }

            sf::Int32 enemydatax, enemydatay;
            packet2 >> enemydatax;
            packet2 >> enemydatay;
            cout << "enemy x: " << enemydatax << std::endl;
            cout << "enemy y: " << enemydatay << std::endl;
            player2.x = enemydatax;
            player2.y = enemydatay;
            player2.shape.setPosition(player2.x, player2.y);
            player1.shape.setPosition(player1.x, player1.y);
            window.clear(sf::Color::Black);

            window.draw(player2.shape);
            window.draw(player1.shape);
            window.display();

            //Send our clients position to the server
            sf::Packet packet1;
            datax = player1.x;
            datay = player1.y;
            packet1 << datax << datay;


//            if (client.send(packet1) != sf::Socket::Done)
//            {
//                cout << "Couldn't send data to client.\n";
//            }
//            else
//            {
//                cout << "Data sent to client.\n";
//            }

        }
        // use "client" to communicate with the connected client,
        // and continue to accept new connections with the listener
    }
}

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Server and client can't both send and receive at the same time?
« Reply #1 on: October 24, 2014, 08:21:57 pm »
I'm guessing you want non-blocking sockets (http://sfml-dev.org/tutorials/2.1/network-socket.php#non-blocking-sockets), since blocking I/O in your main game loop is a bit problematic even if it does work.

See also: https://github.com/SFML/SFML/wiki/FAQ#network-internet-network

Since you have cout's in your code, it would be nice to know what actually got printed out.  And you should probably cout something when connect() fails so we can rule out any problems with that.

zakkor

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Server and client can't both send and receive at the same time?
« Reply #2 on: October 24, 2014, 08:32:24 pm »
I'll change it to non-blocking later, I think, after I get these working... :)
added an error message for when connect() fails.
unfortunately, nothing at all gets printed when i run both the server and the client. it's still waiting for a connection i presume (from the blocking aspect of the socket) but no error messages are displayed

zakkor

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: Server and client can't both send and receive at the same time?
« Reply #3 on: October 25, 2014, 03:00:42 pm »
I managed to fix it. To anyone else that might be wondering about this, here's the issue:
I took a look at the SFML socket example in more detail, and noticed that you have to alternate the sending and receiving for server and client:
Example:
server:
 - first sends, then receives
client:
 - first receives, then sends
This fixed the issue, and now it's no longer laggy AT all.
Here's a pastebin of the fixed code if anyone needs it:
http://pastebin.com/GHTif2Xj

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Server and client can't both send and receive at the same time?
« Reply #4 on: October 25, 2014, 03:31:18 pm »
I don't think it is a fix at all, just luck.

If you unroll the client and server main loops, you get the same thing: send/receive/send/receive/send/receive/... there's not one before the other, because the whole thing loops. Swapping the receive and send calls changes nothing. If I had to guess why your second code works better than the first one, I'd say that this is because of vertical-sync. With vertical-sync enabled, window.display() is what takes most of the main loop's time. And since you have the receive call before, and the send call after, it makes the client and server somehow synchronized so that when one sends, the other is receiving and the other way round.

But back to the real problem now. When the you call receive() on client side, the whole execution is blocked until some data is received. Now everything's fine if the server just issued a call to send(). But what if both client and server arrive at the receive() call at the same time? Both will be stuck waiting for some data from each other. Which will never happen because they can't send as long as they are waiting to receive something.

So I think that your design is flawed. You should read more networking tutorials (I mean generic ones, not specifically tied to a library). In short: make your sockets non-blocking if you want them to stay in the main thread (best option) or use threads to avoid blocking the application while you're waiting for network data.
Laurent Gomila - SFML developer