7
votes

Dans la mise en réseau C ++, utiliser SELECT DOI-VOUS DOIS Écouter () et acceptez

J'essaie d'autoriser plusieurs clients à se connecter à un hôte à l'aide de SELECT. Dis-je connecter chacun un, dites-leur de passer à un autre port, puis de vous reconnecter sur un nouveau port? Ou sélectionnerons-moi permettez-moi de connecter plusieurs clients au même port?

Ceci est le code client: p> xxx pré>

Ceci est le code du serveur: p>

        int rv = getaddrinfo(NULL, port, &hints, &res);
    int yes = 1;//Not sure what this is for, found it in Beej's
    if(rv != 0){
            cout<< "Error, nothing matches criteria for file descriptor.\n";
            exit(1);
    }
    int fdInit;
    for(temp = res; temp != NULL; temp = temp->ai_next){
            if((fdInit = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol)) == -1){
                    cout << "This is not the fd you're looking for.  Move along.\n";
                    continue; //This is not the fd you're looking for, move along.
            }

            if(setsockopt(fdInit, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
                    cout << "Doom has fallen upon this set socket.\n";
                    perror("setsockopt");
                    exit(1); //Unable to set socket, exit program with code 1
            }

            if(bind(fdInit, temp->ai_addr, temp->ai_addrlen) == -1){
                    cout << "Could not bind fd\n";
                    close(fdInit);
                    continue; //Could not bind fd, continue looking for valid fd
            }
            break; //If a valid fd has been found, stop checking the list
    }
    if(temp==NULL){
            cout<<"Server failed to bind a socket\n";
            exit(2);
    }

    cout << fdInit << endl;
    //Setup the file descriptor for initial connections on specified port
    freeaddrinfo(res);
    FD_SET(fdInit, &masterSet);


0 commentaires

3 Réponses :


3
votes

De nombreux clients peuvent se connecter au même port

Vous devez d'abord écouter, puis sélectionnez

Lorsque SELECT vous indique, vous avez une nouvelle connexion, puis acceptez. Il vous indique que le client connecté en signalant une lecture sur votre socket FD.


0 commentaires

1
votes

Vous devez marquer la prise de serveur en tant que telle ( écouter (2) ) mais seulement appeler accepter (2) lors de votre retour de Sélectionnez (2) Quand il devient lisible - cela signifie une nouvelle demande de connexion est en attente.

Veuillez noter que si vous ne travaillez pas avec sockets non bloquants Il y a une chance pour une course entre SELECT (2 ) retourner et appeler accepter (2) - le client de connexion peut déposer la tentative pendant cette période - afin que vous puissiez toujours bloquer.


0 commentaires

13
votes

Les connexions TCP sont identifiées par l'adresse IP et le numéro de port de les deux extrémités em> de la connexion. Il convient donc d'avoir beaucoup de clients (qui auront généralement des numéros de port attribués au hasard) pour se connecter à un seul porteur de serveur.

Vous créez une prise et Bind () code> à un port sur lequel ÉCOUTER () CODE>, puis attendez que les clients viennent frapper dessus. Si vous ne vous dérangeez pas de bloquer, vous pouvez simplement appeler accepter () code> sur elle directement, mais vous ne ferez aucune boucle de délai ou rien. Sinon, vous pouvez SELECT () CODE> sur la prise d'écoute, qui sera lisible lorsqu'un client tente de se connecter, puis d'appeler accepter () p> p> P> P> P> P> P > accepter () code> retournera une prise nouvellement créée, qui est la prise réelle pour parler au client. La prise d'écoute d'origine continue d'écouter, et plus de connexions peuvent être acceptées dessus. P>

Il est typique d'utiliser un Sélectionnez () CODE> boucle pour rechercher la lisibilité sur la prise d'écoute et tout des prises connectées. Ensuite, lorsque SELECT () CODE> Retourne que vous vérifiez simplement si la prise d'écoute a été lisible, et si oui, accepte () code>; Sinon, recherchez une prise connectée lisible et manipulez-la. P>

fd_set fds;
int max = 0, reuse = 1;
struct timeval tv;
int server;
std::vector<int> connected;

// create server listening socket
server = socket(PF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); // optional, but recommended
if (bind(server, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
    // error, could not bind server socket
}
if (listen(server, 8) < 0) {
    // error, could not listen on server port
}

// loop looking for connections / data to handle
while (running) {
    FD_ZERO(&fds);
    FD_SET(server, &fds);
    if (server >= max) max = server + 1;

    for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
        FD_SET(*it, &fds);
        if (*it >= max) max = *it + 1;
    }

    tv.tv_sec = 2; tv.tv_usec = 0;
    if (select(max, &fds, NULL, NULL, &tv) > 0) {
        // something is readable
        if (FD_ISSET(server, &fds)) {
            // it's the listener
            connected.push_back(accept(server, (struct sockaddr *)&addr));
        }
        for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
            if (FD_ISSET(*it, &fds)) {
                // handle data on this connection
            }
        }
    }
}


0 commentaires