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

Author Topic: Continually accepting connections using Udp  (Read 2254 times)

0 Members and 1 Guest are viewing this topic.

The New Guy

  • Newbie
  • *
  • Posts: 15
    • View Profile
    • Email
Continually accepting connections using Udp
« on: May 07, 2013, 05:51:26 am »
Hey guys, so I am attempting to work on a Server -> Multiple client based application. Right now I have it set up so I can send each client messages from the server application. The only problem is my program won't continually accept connections. Right now it is set up to accept a connection, I can say a message to that client and then I can connect another client.

I have been working off the CodingMadeEasyTutorials, but I can't seem to figure this one out. Basically I guess what I am asking is how do I continually check for new connections and be able to type from the server at the same time? Do I need to already have to set up some sort of login server?

Any help would be appreciated.

Server Code for Reference

#include<SFML/Graphics.hpp>
#include<SFML/Network.hpp>
#include<string>
#include<iostream>
#include<conio.h>
#include<vector>
 
using namespace std;
 
int main()
{      
  sf::IpAddress ip = sf::IpAddress::getPublicAddress();
     
    sf::UdpSocket socket;
    char connectionType, mode;
    char buffer[2000];
    std::size_t received;
    std::map<unsigned short, sf::IpAddress> computerID;
    std::string text =  "Connected to:"  ;
 
    //std::cout << ip << std::endl;

     socket.bind(2000);
 
    //socket.setBlocking(false);
 
        //char answer = 'b';
        //do
        //{
                //cin >> answer;
        //}while(answer != 'a');
 
    bool done = false;
 
    while(!done)
    {
                sf::IpAddress rIp;
                unsigned short port;
                socket.receive(buffer, sizeof(buffer), received, rIp, port);
                if(received > 0)
                {
                        computerID[port] = rIp;
                        cout << "someone has connected" << endl;
                }
               

            std::getline(cin, text);
            std::map<unsigned short, sf::IpAddress>::iterator tempIterator;
            for(tempIterator = computerID.begin(); tempIterator != computerID.end(); tempIterator++)
                socket.send(text.c_str(), text.length() + 1, tempIterator->second, tempIterator->first);
    }
 
    system(" pause" );
 
    return 0;
}
 

Client Code for Reference
#include<SFML/Graphics.hpp>
#include<SFML/Network.hpp>
#include<iostream>
#include<conio.h>
#include<vector>

using namespace std;
 
int main()
{

        sf::UdpSocket socket;
        std::string text =  "Connected to:"  ;
        char buffer[2000];
    std::size_t received;
    unsigned short port;
 
    std::cout << " Set port number:"  ;
    cin >> port;

        socket.bind(port);

 
       
        std::string sIP;
        std::cout << " Enter server ip: " ;
                cin >> sIP;
        sf::IpAddress sendIP(sIP);
        socket.send(text.c_str(), text.length() + 1, sendIP, 2000);

        bool done = false;
        while(!done)
        {
            sf::IpAddress tempIp;
            unsigned short tempPort;
            socket.receive(buffer, sizeof(buffer), received, tempIp, tempPort);
            if(received > 0)
                std::cout << " Received: "  << buffer << std::endl;
        }
    return 0;
}
 

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Continually accepting connections using Udp
« Reply #1 on: May 07, 2013, 04:29:06 pm »
You must first understand that UDP is a connectionless protocol. There is no such thing as a "connection" using UDP. You can create your own connection management mechanism on top of UDP but you will have to manage everything yourself. As such saying "accept a connection" is generally wrong in this context. You merely receive packets and associate them with an opposite endpoint. The OSI stack is divided into multiple layers. Each of these layers have an addressing scheme of some sort. The most popular one would be layer 3 - the network layer, which uses IP addresses to identify endpoints. If you go up to layer 4 you have 2 addresses. One denotes the protocol type, TCP, UDP etc. and the other is specific to the protocol itself, so e.g. UDP port 53 and TCP port 53 are different endpoints.

As such
Code: [Select]
computerID[port] = rIp;is not fully correct, because an endpoint is only uniquely identified by a pair consisting of (IP address, UDP port number). With your map, multiple IP addresses using the same port can be identified as the same client because you only use the port number as the map key.

You must also understand that the call to .receive() is blocking unless the socket is set to non-blocking mode. It will wait there until it receives something, and in that time your application can't do anything else useful. The same goes for cin. It waits for input from stdin and blocks until the carriage return is encountered. If you want to be able to type and serve clients at the same time. Read from cin in a separate thread.

If you don't want to use non-blocking sockets, you can make use of selectors. They are well documented in the documentation so you should read up on that if you are interested.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).