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

Author Topic: Undesired behaviour in Linux networking code  (Read 1857 times)

0 Members and 2 Guests are viewing this topic.

radario

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Undesired behaviour in Linux networking code
« on: June 13, 2012, 11:41:26 pm »
Hi.

I have a tcp server listening on a thread, wating for connections from clients. When the program is closed, I close the server's socket, but the server keeps accept-ing.

Here's some test code:

#include <stdlib.h>

#include "ServerThreadTest.h"
#include "VBClient.h"
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
#include <vector>
#include <iostream>

namespace ThreadTest {

    class Server {
    public:

        Server(int port) : _port(port), _running(false), _socket(new sf::TcpListener()) {
            std::cout << "Server blocking: " << _socket->isBlocking() << std::endl;
            sf::TcpSocket::Status status = _socket->listen(port);

            if (status != sf::TcpSocket::Done) {
                _running = false;
            } else {
                _running = true;
            }
        };

        ~Server() {
            this->close();

            if (_socket) {
                delete(_socket);
            }
            _socket = NULL;
           
        };

        void run() {
            while (_running) {
                sf::TcpSocket socket;

                std::cout << "Server: waiting for a connection ..." << std::endl;

                sf::TcpSocket::Status status = _socket->accept(socket);

                if (status == sf::TcpSocket::Done) {
                    std::cout << "Server: client incoming" << std::endl;
                    //                    sockets.push_back(socket);

                    socket.disconnect();

                } else {
                    switch (status) {
                        case sf::TcpSocket::Disconnected:
                            std::cout << "DISCONNECTED" << std::endl;
                            break;
                        case sf::TcpSocket::Error:
                            std::cout << "ERROR" << std::endl;
                            break;
                        case sf::TcpSocket::NotReady:
                            std::cout << "NOT READY" << std::endl;
                            break;
                    }

                    _running = false;
                }
            }

            std::cout << "Server: I leave" << std::endl;

        };

        void running(bool b) {
            _running = b;
        };

        bool running() {
            return _running;
        };

        void close() {

            // Useless
            _running = false;

            if (_socket) {
                _socket->close();
            }
        };

    private:
        int _port;
        bool _running;
        sf::TcpListener *_socket;

    };
};

int ServerThreadTest() {

    const int porta = 8080;

    ThreadTest::Server server(porta);

    sf::Thread thread(&ThreadTest::Server::run, &server);

    thread.launch();

    sf::IpAddress address("localhost");
    for (int i = 0; i < 10; i++) {

        std::cout << "Connection try #" << i << std::endl;

        sf::TcpSocket socket;

        if (socket.connect(address, porta, sf::seconds(1)) != sf::TcpSocket::Done) {
            std::cout << "Connection error" << std::endl;
        }
       
        sf::sleep(sf::seconds(1.0f));

    }

    server.close();

    std::cout << "I'd leave, if you don't mind..." << std::endl;

    return EXIT_SUCCESS;
}

This behaviour is related to what is described in this StackOverflow post:

http://stackoverflow.com/questions/9365282/c-linux-accept-blocking-after-socket-closed

I'm willing to send a signal to that thread, but it seems it's not possible to get the thread handle with the current API.

terminate() the thread is not an option, since it leaves the file descriptor opened.

Having a non-blocking socket with small sleeps between accept()s is quite ugly, too.

Another workaround is to put _running to false, then starting another connection to the server, so that the socket will close in its thread.

Is there a way to manage this situation cleanly?

Thanks in advance:)

radario

radario

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Undesired behaviour in Linux networking code
« Reply #1 on: June 14, 2012, 11:40:51 pm »
Hi.

I have to add that there's something strange about the Network library. I have an SFML application in which I open a server on a port, and on the first run the TcpListener binds succesfully. But then, on the next run, regardless of how the application closed (gracefully, errors and so on), the TcpListener fails to bind the port. This behaviour persists for a certain amount of time (sometimes - rarely - it just doesn't happen) and then in the end the TcpListener binds again the port.
Out of curiosity I downloaded and compiled the Poco library (http://pocoproject.org), which provides a network library, and I can bind succesfully at every run with no problems.
Am i missing something, or the Network library needs some debugging? I'm running Archlinux x86_64, if it helps.

ciao!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Undesired behaviour in Linux networking code
« Reply #2 on: June 15, 2012, 08:13:28 am »
See this: https://github.com/SFML/SFML/issues/150

I have no idea about your initial problem, sorry.
Laurent Gomila - SFML developer

radario

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Undesired behaviour in Linux networking code
« Reply #3 on: June 17, 2012, 10:37:15 am »
Hi.

I'll temporarily switch to another network library, for this run:)
By the way, I tried the code on windows and it runs correctly and consistently, so I'll debug the issue on Linux as soon as possible:)

ciao!