SFML community forums

Help => Network => Topic started by: Grimlen on September 17, 2012, 09:16:17 am

Title: Server can only receive one message at a time?
Post by: Grimlen on September 17, 2012, 09:16:17 am
I haven't tested client -> server -> client yet, just client -> server for now.
Unfortunately, I'm only able to send one message per connection.
Client
int main()
{
        sf::SocketTCP Client;
    // Create the main rendering window
    sf::RenderWindow App(sf::VideoMode(480, 320, 32), "Window");
        const sf::Input& Input = App.GetInput();
    cout << "Type LEFT to connect, RIGHT to send a message, UP to disconnect" << endl;
    // Start game loop
    while (App.IsOpened())
    {
        // Process events
        sf::Event Event;
        while (App.GetEvent(Event))
        {
                        if(Input.IsKeyDown(sf::Key::Left)){
                                if (Client.Connect(4567, "127.0.0.1") != sf::Socket::Done)
                                {
                                        // Error...
                                        cout << "error" << endl;
                                }
                                else cout << "connected" << endl;
                        }
                        else if(Input.IsKeyDown(sf::Key::Right)){
                                cout << "right pressed" << endl;
                                char Buffer[] = "Hi guys !";
                                if (Client.Send(Buffer, sizeof(Buffer)) != sf::Socket::Done)
                                {
                                        // Error...
                                        cout << "error sending message" << endl;
                                }
                        }
                        else if(Input.IsKeyDown(sf::Key::Up)){
                                Client.Close();
                                cout << "disconnected" << endl;
                        }
            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                App.Close();
        }

        // Clear the screen (fill it with black color)
        App.Clear(sf::Color(255, 255, 255));

        // Display window contents on screen
        App.Display();
    }

    return EXIT_SUCCESS;
}
 

Left button connects, right button sends a message: "Hi guys !", up button disconnects/closes the socket.
Now on my server...
Server
void ThreadFunction(void* UserData)
{
        Server *server = (Server*)UserData;
        char Buffer[128];
        std::size_t Received;

        while(true){
                sf::IPAddress ClientAddress;
                if (server->Listener.Accept(server->Client, &ClientAddress) != sf::Socket::Done)
                {
                        // Error...
                        //cout << "Error listening..." << endl;
                }
                else{
                        cout << "Got a connection!" << endl;
                }

                if (server->Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
                {
                        // Error...
                        continue;
                }
                else{
                        cout << "Message: " << Buffer << endl;
                }
        }
}
 

I can connect, and send a message, but just one message.
If I disconnect and connect again, I can send a message, but only one.

Not sure what's going on. I should be able to send multiple ones.
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 17, 2012, 09:24:07 am
Your server does this:
infinite loop
{
    wait for a new client
    wait a message from this client
}
So after it has received a message, it waits for a new client.

And in your client code, you shouldn't mix events and inputs. If you want to react to single key press events, you should use the information contained in your sf::Event structure inside your event loop.
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 17, 2012, 05:31:54 pm
Not really sure how to fix the problem for the server.
Don't we need to continuously listen for new connections using a loop?

I'm  a bit clueless on where in my program these codes need to be.
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 17, 2012, 05:35:59 pm
Quote
Don't we need to continuously listen for new connections using a loop?
Yes, but while the socket waits for new connections, the entire thread is blocked and cannot do anything else.

The solutions that you can use are:
- switch to non-blocking sockets
- use more threads to avoid actions blocking each other
- use a selector

See the tutorials and documentation for more details :)
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 17, 2012, 06:32:32 pm
Well I tried non-blocking sockets:
        Listener.SetBlocking(false);
        Client.SetBlocking(false);
 

Can still send one message per connection.

I've also tried using different threads:
void ThreadNet(void* UserData){
        Server *server = (Server*)UserData;
        char Buffer[128];
        std::size_t Received;
        while(true){
                if (server->Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
                {
                        // Error...
                        continue;
                }
                else{
                        cout << "Message: " << Buffer << endl;
                }
        }
}

void ThreadFunction(void* UserData)
{
        Server *server = (Server*)UserData;

        while(true){
                sf::IPAddress ClientAddress;
                if (server->Listener.Accept(server->Client, &ClientAddress) != sf::Socket::Done)
                {
                        // Error...
                        //cout << "Error listening..." << endl;
                }
                else{
                        cout << "Got a connection!" << endl;
                }
        }
}
 

Still just one message per connection...
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 17, 2012, 08:26:41 pm
I've also tried using a selector.
Only this time, I can't receive any messages, besides the one when they connect to my server:
void ThreadFunction(void* UserData)
{
        Server *server = (Server*)UserData;
        char Buffer[128];
        std::size_t Received;
        while(true){
                unsigned int NbSockets = server->Selector.Wait();
                for(unsigned int i = 0; i < NbSockets; ++i){
                        sf::SocketTCP Socket = server->Selector.GetSocketReady(i);
                        //Look for new connections
                        if(Socket == server->Listener){
                                sf::IPAddress Address;
                                sf::SocketTCP Client;
                                server->Listener.Accept(Client, &Address);
                                cout << "Got a client" << endl;
                                server->Selector.Add(Client);
                        }
                        //Read data from clients
                        else{
                                sf::Packet Packet;
                                if(Socket.Receive(Packet) == sf::Socket::Done){
                                        //Get the message
                                        std::string Message;
                                        //Put whatever is in the Packet to the string
                                        Packet >> Message;
                                        cout << "Message: " << Message << endl;
                                }
                                else{
                                        server->Selector.Remove(Socket);
                                }
                        }
                }
        }

}
 

What I'm using to send a message:
                                char Buffer[] = "Hi guys !";
                                if (Client.Send(Buffer, sizeof(Buffer)) != sf::Socket::Done)
                                {
                                        // Error...
                                        cout << "error sending message" << endl;
                                }
 
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 17, 2012, 10:13:37 pm
But... what is your main thread doing while the network thread is running?
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 18, 2012, 05:29:45 am
It's asking for commands.
Here's my entire main.cpp for my server:
/************************************************************
SERVER
************************************************************/

#include <iostream>
#include <string>
#include "Server.h"
#include <SFML/System.hpp>
using namespace std;

int command(Server *s, std::string line);
void ThreadFunction(void* UserData);

bool running;

void ThreadFunction(void* UserData)
{
        Server *server = (Server*)UserData;
        char Buffer[128];
        std::size_t Received;
        while(true){
                unsigned int NbSockets = server->selector.Wait();
                for(unsigned int i = 0; i < NbSockets; ++i){
                        sf::SocketTCP Socket = server->selector.GetSocketReady(i);
                        //Look for new connections
                        if(Socket == server->Listener){
                                sf::IPAddress Address;
                                sf::SocketTCP Client;
                                server->Listener.Accept(Client, &Address);
                                cout << "Got a client" << endl;
                                server->selector.Add(Client);
                        }
                        //Read data from clients
                        else{
                                sf::Packet Packet;
                                if(Socket.Receive(Packet) == sf::Socket::Done){
                                        //Get the message
                                        std::string Message;
                                        //Put whatever is in the Packet to the string
                                        Packet >> Message;
                                        cout << "Message: " << Message << endl;
                                }
                                else{
                                        server->selector.Remove(Socket);
                                }
                        }
                }
        }

}

//Entry
int main(){
        Server server;
        sf::Thread thread(&ThreadFunction, &server);
        running = true;
        thread.Launch();
        string line;
        cout << "=========================="    << endl;
        cout << "Welcome to the NetServer."             << endl;
        cout << "=========================="    << endl;
        cout << endl;
        cout << "===================================================="          << endl;
        cout << "Enter a command. For a list of commands type \"help\"."        << endl;
        cout << "===================================================="          << endl;
        while (running){
                int ret;
                if(std::getline(cin, line)){
                        if(ret = command(&server, line) != 0)
                                return ret;
                }
        }
}

//Loop
int command(Server *server, std::string line){
        cout << endl;
        //Process line
        if(line == "help"){
                cout    << "<LIST OF COMMANDS:>" << endl;
                cout    << "help        - Displays help"        << endl
                                << "start       - Starts the server"    << endl
                                << "stop        - Stops the server"     << endl;
        }
        else if(line == "start"){
                server->start();
        }
        else if(line == "stop"){
                server->stop();
        }
        else{
                cout << endl;
                cout << "=========================" << endl;
                cout << "Invalid. Enter a command." << endl;
                cout << "=========================" << endl;
                return 0;
        }
        cout << endl;
        cout << "================" << endl;
        cout << "Enter a command." << endl;
        cout << "================" << endl;
        return 0;
}
 
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 18, 2012, 08:18:12 am
Can you please use the code=cpp tag so that I can stop editing all your messages?
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 18, 2012, 08:25:38 am
Sorry, didn't know I could do that.
Do you know what may be the problem?
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 18, 2012, 09:13:55 am
Can you show the code of the Server class?
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 18, 2012, 11:16:15 pm
#include "Server.h"
#include <iostream>
using namespace std;
Server::Server(){
        started = false;
        Listener.SetBlocking(false);
}

void Server::start(){
        if(!started){
                //Check TCP Socket
                cout << "Attempting to listen on TCP port: 4567...." << endl;
                if (!Listener.Listen(4567))
                {
                        // Error...
                        cout << "Could not listen on TCP port: 4567." << endl;
                        return;
                }
                cout << "Listening on port 4567" << endl;
                started = true;
                cout << "Server started." << endl;

                selector.Add(Listener);
        }
        else{
                cout << "Server is all ready running." << endl;
        }
}

void Server::stop(){
        cout << "Stopping server..." << endl;
        started = false;
        unsigned int NbSockets = selector.Wait();
        for(unsigned int i = 0; i < NbSockets; ++i){
                selector.GetSocketReady(i).Close();
        }
}
 
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 19, 2012, 07:48:47 am
Don't mix selectors and non-blocking sockets, it doesn't make sense. And don't forget to check the result of the Accept function.
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 20, 2012, 06:39:48 am
Well I've redone my entire server and client.
Unfortunately I'm still getting the same result as before.
I can only get one message at a time per client/connection....

CLIENT:
/************************************************************
CLIENT
************************************************************/

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

using namespace std;
////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
        //Server we are connecting to (via TCP)
        bool closedConnection = false; //if we closed the socket yet or not
        sf::SocketTCP Server;
        Server.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
        char Message1[] = "Hello!";
        char Message2[] = "Again!";
        cout << "test" << endl;
       
        if (Server.Connect(4567, "127.0.0.1") != sf::Socket::Done)
        {
                // Error...
                cout << "Unable to connect to server" << endl;
        }
        else{
                cout << "Connected to server" << endl;
        }
        if (Server.Send(Message1, sizeof(Message1)) != sf::Socket::Done)
        {
                // Error...
        }
        else{
                cout << "Sent message to server" << endl;
        }
        if (Server.Send(Message2, sizeof(Message2)) != sf::Socket::Done)
        {
                // Error...
        }
        else{
                cout << "Sent message to server" << endl;
        }
       
    // Create the main rendering window
    sf::RenderWindow App(sf::VideoMode(480, 320, 32), "Window");
        const sf::Input& Input = App.GetInput();
    // Start game loop
    while (App.IsOpened())
    {
        // Process events
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            // Close window : exit
                        if (Event.Type == sf::Event::Closed){
                                //Player decided to close the program
                                //Check if we've closed the socket yet
                                //If we haven't, close it
                                if(!closedConnection){
                                        Server.Close();
                                        closedConnection = true;
                                }
                App.Close();
                        }
        }

        // Clear the screen (fill it with black color)
        App.Clear(sf::Color(255, 255, 255));

        // Display window contents on screen
        App.Display();
    }
        //We come to the end of the program
        //Check if we've closed the socket yet
        //If we haven't, close it
        if(!closedConnection){
                Server.Close();
                closedConnection = true;
        }
    return EXIT_SUCCESS;
}
 

SERVER:
/************************************************************
SERVER
************************************************************/

#include <iostream>
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
using namespace std;

//Entry
int main(){
        sf::SocketTCP Client;
        sf::IPAddress ClientAddress;
        sf::SocketTCP Listener;
        Client.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
        Listener.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
        //Buffer to receive messages
        char Buffer[128];
        //How many messages we've received
        std::size_t Received;
        bool running = true;
        if (!Listener.Listen(4567))
        {
                // Error...
                cout << "Unable to listen on TCP port: 4567" << endl;
        }
        else{
                cout << "Listening on TCP port: 4567" << endl;
        }
        while(running){
                //Waits until a incoming connection arrives
                if (Listener.Accept(Client, &ClientAddress) != sf::Socket::Done)
                {
                        // Error...
                        //cout << "Unable to accept any incoming connections" << endl;
                }
                else{
                        cout << "Accepted a Client!" << endl;
                }
                if (Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
                {
                        // Error...
                        //cout << "Unable to receive any messages from client." << endl;
                }
                else{
                        cout << "Message: " << Buffer << endl;
                }
        }
}
 
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 20, 2012, 07:57:42 am
I'd like to test your code, but it uses SFML 1.6. Don't you want to upgrade to SFML 2 (which is a much better version anyway)?
Title: Re: Server can only receive one message at a time?
Post by: Grimlen on September 20, 2012, 06:56:13 pm
There doesn't appear to be any tutorials on version 2.0 for networking (unless I saw wrong).
I've got a roster of people all ready setup for 1.6 and we'd rather not switch as we've been working
hard with 1.6. Anyways....
To be honest I'd rather want to know what's wrong with my code now.
I've gone over the tutorial on the TCP section and I'm absolutely dumbfounded why I can only
get just one message per connection.....

Could you possibly test it to determine what's wrong? I've been stuck on this for a while.
Title: Re: Server can only receive one message at a time?
Post by: Qix on September 20, 2012, 07:21:54 pm
I would recommend using threads, as non-blocking sockets are a bit more complicated than they appear.
Title: Re: Server can only receive one message at a time?
Post by: Laurent on September 20, 2012, 08:37:38 pm
Quote
Could you possibly test it to determine what's wrong? I've been stuck on this for a while.
My free time is really reduced to minimum, so I'm a little lazy and never test 1.6 code. Also because I have stopped maintaining SFML 1.6 3 years ago and a lot of bugs have been fixed in SFML 2. Sorry.

Although the tutorials are not written yet, networking hasn't changed much and you should be able to convert your code easily with the 1.6 tutorials and the 2.0 API documentation (which is much more detailed and has useful examples).

Quote
I would recommend using threads, as non-blocking sockets are a bit more complicated than they appear.
Not really. At least not for this use case.
Title: Re: Server can only receive one message at a time?
Post by: Qix on September 24, 2012, 12:21:34 am
Well depending on the situation, the packet-end byte in a non-blocking socket system isn't recognized by the client or server so certain protocols will appear to cluster packets together.
Title: Re: Server can only receive one message at a time?
Post by: StormWingDelta on October 28, 2012, 07:08:32 pm
another thing you could do is multithreading your server so it can have more than one client at a time.  It's good for when you want any number of clients on a given server but it helps if the code is as reuseable as you can get it.  As soon as I get done fighting with an Object/Memory manager I'll see what dig up on issues like this.
Title: Re: Server can only receive one message at a time?
Post by: Qix on October 29, 2012, 08:49:59 am
another thing you could do is multithreading your server so it can have more than one client at a time.  It's good for when you want any number of clients on a given server but it helps if the code is as reuseable as you can get it.  As soon as I get done fighting with an Object/Memory manager I'll see what dig up on issues like this.

Multithreading with sockets is generally a bad idea, usually if you do it wrong. A process can only have ~2000 threads (a lot of the time much less, depending on the system and whatnot), so having a big server can screw things up. Plus processor affinity can play an issue if a client is sending malicious content; it can potentially slow down the main thread, or another crucial thread.

If you want to have something similar to multithreading, it's best practice to use non-blocking sockets.