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

Author Topic: Simple chat, simple problem?  (Read 6017 times)

0 Members and 1 Guest are viewing this topic.

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Simple chat, simple problem?
« on: June 30, 2013, 04:23:24 pm »
Hi, I am trying to make a simple chat for a game I am working at. The idea is to have one thread running the game itself, and maybe sending chat messages, and another only for receiving chat messages. I created a simple class called Chat which has two functions, one called add_string( std::string s ) and the other render().
The problem is that when trying to use add_string from the receiving thread, called "server" in my program it doesn't work properly. I have tried to use std::mutex to ensure the Chat object is not used simultaneously by the two threads. What happens is that the Chat object does not get the correct string but instead only parts of it or in most cases, an empty string. There is a third thread in this example program, the one called "client", used only to send messages. The Chat class works fine itself and so does the network parts of this program, so I figured the problem must be thread related :P.  So why is the "server" thread not able to properly add string objects to the chat object? Here's the code:

class Chat {
private:
        const static int MAX_LINES = 25;
        int linewidth;
        sf::IntRect size;
        sf::Font font;
        sf::Text tempText;
        std::deque<sf::Text> chatlog;
public:
        Chat();
        void add_string( std::string s );
        void render();
};

// Chat.cpp
Chat::Chat() {
        linewidth = 20;

        size.height = SCREEN_HEIGHT;
        size.width = SCREEN_WIDTH / 2;
        size.top = 0;
        size.left = SCREEN_WIDTH / 2;

        if (!font.loadFromFile("times.ttf"))
        {
           // error...
                //return 0;
        }
        tempText.setFont(font);        
        tempText.setCharacterSize(15);
        tempText.setColor(sf::Color::White);
        tempText.setStyle(sf::Text::Bold );
}

void Chat::add_string( std::string s ) {
        // Move all other strings one line up.
        for( auto it = chatlog.begin(); it < chatlog.end(); it++ ) {
                sf::Vector2f temp = it->getPosition();
                temp.y -= linewidth;
                it->setPosition( temp );
        }
        // Add the new string to the bottom of the chat.
        tempText.setString( s );
        int xPos = size.left;
        int yPos = size.top + size.height - linewidth;
        tempText.setPosition( sf::Vector2f( xPos, yPos ) );
        chatlog.push_back( tempText );

        if( chatlog.size() > MAX_LINES ) {
                chatlog.pop_front();
        }      
}

void Chat::render() {
        for( auto it = chatlog.begin(); it < chatlog.end(); it++ ) {
                window.draw( *it );
        }
}

#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Network.hpp>
#include <SFML/Graphics.hpp>
#include "globals.h"
#include "chat.h"
#include <string>
#include <thread>
#include <mutex>

bool quit = false;

#define SERVER_PORT 54000
#define CLIENT_PORT 54001
#define EXIT_PORT 54002

void server( Chat* p );
void client();

int apa = 0;


std::mutex chatMutex;

int main(int argc, char* argv[])
{
        Chat chat;
        chat.add_string( "BLALBALBLAL LBLBLABLABL " );
        chat.add_string( "BLALBALGKDSGKSgBLAL LBLBLABLABL " );
        chat.add_string( "CPMONGOBLABL " );

        std::thread myClientThread( client );
        std::thread myServerThread( server, &chat );

        sf::UdpSocket socket;
        //// bind the socket to a port
        if ( socket.bind( EXIT_PORT ) != sf::Socket::Done )
        {
            // error...
        }
        sf::IpAddress recipient = sf::IpAddress::getLocalAddress();
        char data[10] = "Byebye!";

        while( !quit ) {

                window.clear(sf::Color::Black);

                chatMutex.lock();
                chat.render();
                chatMutex.unlock();            

                window.display();
        }

        myServerThread.join();
        myClientThread.join(); 

        return 0;
}

void client() {
        sf::UdpSocket socket;
        // bind the socket to a port
        if (socket.bind( CLIENT_PORT ) != sf::Socket::Done)
        {
            // error...
        }

        char enteredIP[20];
        std::cout << "Enter the IP you want to connect to" << std::endl;
        std::cin.getline( enteredIP, 20 );
        std::cout << enteredIP << std::endl;

        sf::IpAddress recipient = enteredIP;
        unsigned short port = SERVER_PORT;

        while( !quit ) {
                sf::Packet packet;
                std::string input;
               
                std::getline( std::cin, input );
                packet << input;

                if (sf::Keyboard::isKeyPressed( sf::Keyboard::Return ) ) {
                        if (socket.send(packet, recipient, port) != sf::Socket::Done) {
                                 // error...
                        }
                        sf::Time t = sf::milliseconds( 500 );
                        sf::sleep( t );
                }
        }
}

void server( Chat* p ) {

        sf::UdpSocket socket;
        // bind the socket to a port
        if ( socket.bind( SERVER_PORT ) != sf::Socket::Done )
        {
            // error...
        }
       
        sf::IpAddress sender;
        unsigned short port;

        while( !quit ) {
                sf::Packet packet;
                std::string receivedString;

                if ( socket.receive( packet, sender, port ) != sf::Socket::Done ) {
                    // error...
                }
               
                packet >> receivedString;
                chatMutex.lock();
                p->add_string( receivedString );
                chatMutex.unlock();    
        }
}
« Last Edit: July 03, 2013, 09:09:24 pm by Laurent »

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #1 on: July 03, 2013, 06:15:29 pm »
No one? To clarify things... The class chat, the sending and receiving parts works fine independently. The problem seems to be that the function add_string( std::sting s ) does not work properly when called from the "server" thread. I do not know if this problem is sfml related at all, but the Chat class has sf::Text members and so on, so I guess it could be.

The Hatchet

  • Full Member
  • ***
  • Posts: 135
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #2 on: July 03, 2013, 09:07:16 pm »
I haven't touched any networking with sfml yet so I can't help with your problem, but if you were to post this under the correct forum of NETWORKING and put your code inbetween the [ code ][ /code ] tags then maybe more people would be apt to give you a reply.
« Last Edit: July 03, 2013, 09:10:16 pm by Laurent »

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Simple chat, simple problem?
« Reply #3 on: July 03, 2013, 10:33:10 pm »
I worked on something similar a few months back. You can read about it/view the source here if it helps.

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #4 on: July 04, 2013, 06:04:33 pm »
I worked on something similar a few months back. You can read about it/view the source here if it helps.

All right, I'll check it out.

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #5 on: July 04, 2013, 06:10:21 pm »
I haven't touched any networking with sfml yet so I can't help with your problem, but if you were to post this under the correct forum of NETWORKING and put your code inbetween the [ code ][ /code ] tags then maybe more people would be apt to give you a reply.

As I wrote in the first post, the network part of program works fine by itself, I know this because when simply using the console to display the received messages, the string is not corrupted. So I figured the problem must be thread related, or system related if you will. ;)

I'm sorry about not using the code tags.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #7 on: July 05, 2013, 01:51:03 pm »
And with that link you want to say what? That UDP is not reliable and that is the reason why the string gets corrupted? As I've already stated, the string gets through fine.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Simple chat, simple problem?
« Reply #8 on: July 05, 2013, 05:43:29 pm »
It was a subliminal recommendation to use TCP sockets instead of UDP sockets. Later down the line you will run into headaches if you try to fix any problems that arise due to this. Retrospective transport layer modification is a path known only to lead to despair.

As for your code, I can't help. Mostly because I can't compile it myself, and that mostly because the code you provided is uncompilable. In this case, you are better off just stepping through your code with a debugger and looking at your variable watch for strange things to happen. If what you say is true and each part does function properly by itself, then debugging them all together shouldn't take too long.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #9 on: July 05, 2013, 07:39:21 pm »
It was a subliminal recommendation to use TCP sockets instead of UDP sockets. Later down the line you will run into headaches if you try to fix any problems that arise due to this. Retrospective transport layer modification is a path known only to lead to despair.

As for your code, I can't help. Mostly because I can't compile it myself, and that mostly because the code you provided is uncompilable. In this case, you are better off just stepping through your code with a debugger and looking at your variable watch for strange things to happen. If what you say is true and each part does function properly by itself, then debugging them all together shouldn't take too long.

I can upload the whole, compilable, project here when I get access to it, which will be in about 2 weeks. In any case, thanks for your response.

JonDoe

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • Email
Re: Simple chat, simple problem?
« Reply #10 on: July 12, 2013, 02:59:35 pm »
The problem has been solved, I moved the threads into the class and used lock_guard instead of just lock and unlock.