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

Author Topic: [SOLVED]How to limit the number of TCP clients  (Read 4151 times)

0 Members and 1 Guest are viewing this topic.

Ivan

  • Newbie
  • *
  • Posts: 32
  • IT geek
    • View Profile
[SOLVED]How to limit the number of TCP clients
« on: August 06, 2013, 05:44:51 pm »
I’m making a simple game with TCP Client/Server communication. In the server I have a TcpListener and SocketSelector.

I want to limit the number of clients that can connect to the server to 4. My question is in SFML as I can tell to the server that if have 4 clients, do not accept more connection requests and stop listening new connections? I try with listener.close() but then does not receive data from the existing 4 players.

Any idea? Thanks.
« Last Edit: August 09, 2013, 12:47:35 pm by Ivan »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: How to limit the number of TCP clients
« Reply #1 on: August 06, 2013, 06:11:56 pm »
I want to limit the number of clients that can connect to the server to 4. My question is in SFML as I can tell to the server that if have 4 clients, do not accept more connection requests and stop listening new connections? I try with listener.close() but then does not receive data from the existing 4 players.
Normally if you stop listening on a socket, it should do just that, stop listening. It shouldn't disconnect all active connections that were created through that listener as well. If this is the case, can you provide an example that shows this? Minimal, self-contained and compileable after copying and pasting the code would be nice. This could be a bug in SFML. Indeed, there recently were some bugs in SFML networking code that were fixed ::).

Another way of rejecting connection attempts is doing just that, rejecting them. What you do is accept() them in the listener using a temporary TcpSocket and just disconnect()/close() them immediately after you accept. This is probably the less brutal way of rejecting clients since they know the server is alive but does not want to accept their connection attempt.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ivan

  • Newbie
  • *
  • Posts: 32
  • IT geek
    • View Profile
Re: How to limit the number of TCP clients
« Reply #2 on: August 07, 2013, 12:09:21 am »
Thanks for your reply binary1248. I tried to accept() and disconnect() socket and it's work ok.

Just I said, if I close the listener, the server doesn't receive more packets from clients. I uploaded a simply code here: http://sdrv.ms/17wMIf5

Basically the server start and listen for client connection request. When arrives one, accepts and send to client the game map, his player id, his player position, number of players and all the player positions. When receive a player position request, check if is avaiable and send this new position for all the players.

In the client side, its connect to server and receive the map game, his id, position and all player positions.
When the player wants to move (with arrow keys: left, right, up, down), send the requested new position to server, if its available, receive an answer and move to it. Also, if receive a position of one rival, set it.

I limited the number of players to 4, when a 5th client attempts to connect, show the error message, close listener and since then, the server doesn't receive the clients data. It's a bug or works properly?

I use SFML 2.1 with Code::Blocks 12.11 (Windows 8 Pro, 32 bits)
« Last Edit: August 07, 2013, 10:31:34 am by Ivan »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: How to limit the number of TCP clients
« Reply #3 on: August 07, 2013, 06:24:13 am »
From the sf::SocketSelector documentation:
Quote
A selector doesn't store its own copies of the sockets (socket classes are not copyable anyway), it simply keeps a reference to the original sockets that you pass to the "add" function. Therefore, you can't use the selector as a socket container, you must store them oustide and make sure that they are alive as long as they are used in the selector.
When you close any socket, not only listeners, you should also remove them from the selector as well, if possible before you close them. The documentation text might lead people to think that as long as their sf::Socket object still exists, selecting on them is permitted no matter what state they are in. This is technically true, however, the behaviour of selecting on a closed socket is not standardized and can lead to anything happening depending on the implementation of the underlying API. As such I recommend just not trying to select on any closed sockets at all.

The problem with your server code is that, after you close the listener, the selector might always return true when you check isReady() on the listener since theoretically it is always ready to be read from in the closed state. Since isReady() always returns true, you will try to accept on a closed socket which would block and lead to your server not processing any other client packets any more. In fact since it blocks forever, it won't do anything at all.

Try removing the listener from the selector before you close it and see if that works.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ivan

  • Newbie
  • *
  • Posts: 32
  • IT geek
    • View Profile
Re: How to limit the number of TCP clients
« Reply #4 on: August 07, 2013, 10:30:09 am »
You are right, I have to remove the listener before close it. My mistake.. Now it's works perfect. Thank you so much binary1248.

sf::TcpListener listener;
sf::SocketSelector selector;
std::vector <sf::TcpSocket*> clients;

listener.listen(2000);
selector.add(listener);

while (true)
{
   if (selector.wait())
   {
       if (selector.isReady(listener))
        {
            sf::TcpSocket *socket = new sf::TcpSocket;
            listener.accept(*socket);
            clients.push_back(socket);
            selector.add(*socket);
            numPlayers++;
            std::cout << "new player connected. Number players: " << numPlayers << std::endl;
           
            if (numPlayers == maxPlayers)
            {
                 std::cout << numPlayers << " players connected, not more allowed." << std::endl;
                 selector.remove(listener);
                 listener.close();
            }

 

 

anything