6
votes

BIND () avec SO_REUSEADDRDRDDRDRDRDR

Ma tâche consiste à implémenter un jeu de deux joueurs joué entre deux ordinateurs connectés via TCP. L'une des exigences est que seul le gagnant reçoit le choix de choix ou non. Si le serveur gagne et décide de ne pas jouer plus avant, le client doit redémarrer en tant que serveur et accepter de nouvelles connexions.

Mon approche: Si le jeu perdu (en mode client), fermez Sockfd et recréez un autre. Ensuite, utilisez setSockopt pour permettre la reprise à l'aide de SO_REUSEADDRDDRDDRDRDDR, puis appelez la liaison. P>

int yes = 1;
if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 )
{
    perror("setsockopt");
}

if ( bind(sockfd, (struct sockaddr*)&svr, sizeof(svr) ) == -1 )
{
    perror("server: bind");
}


6 commentaires

Veuillez afficher votre code (en particulier la pièce autour de setSockopt () ) afin que nous puissions aider.


Êtes-vous sûr que vous fermez correctement le côté serveur (socket d'écoute) avant de tenter de le recréer, dans le code du client? Sur un système Linux, "netstat -tlp" devrait identifier ce qui détient un port TCP ouvert pour écouter dessus ...


Vous essayez de lier () la même adresse {adresse, portnum} deux fois sur une machine? Que vous attendriez-vous?


Eh bien, après avoir attendu 120 secondes, l'approche fonctionne. Je suppose donc que c'est bien de s'attendre à ce que cela fonctionne immédiatement en utilisant SO_REUSEADDRDRDR. Cependant, s'il vous plaît dites-moi si je me trompe.


@BRPOCOCK: Tu as raison. Il y avait un sommeil (1) avant la fermeture de la prise, c'est pourquoi je pouvais être incapable de se lier. Maintenant, ça marche parfaitement. Merci pour le conseil! :)


Je ne sais pas comment les deux ordinateurs se disent sur l'IP et le port à utiliser. Mais en supposant que les adresses IP n'étaient pas typées manuellement pour commencer, pourquoi ne pas simplement choisir un autre port (peut-être +1 de la précédente). Si la reconnexion ultérieure échoue sur le port par défaut, commencez à incrémenter et réessayez.


3 Réponses :


3
votes

SO_REUSeADDRDRDRDRDRDRDRDRDRDRDRDRDRDDR ne vous permet que de lier simultanément à un plus une adresse spécifique , c'est-à-dire le premier serveur écoute sur inaddr_any (toutes les interfaces) et suivantes Les serveurs Écoutez sur différentes adresses d'interface spécifiques.

Second Scénario est lorsque l'écoute de la prise TCP accepte une connexion utilisée, mais la prise d'écoute elle-même est fermée, puis rouverte - disons le processus serveur parent sort et recommence.

Dans les deux cas, vous devez Toujours Set SO_REUSeADDRDRDRDRR SO_REUSEADDRDRDRDRR SO_REUSeADDRDRDRDRUNTRES sur la prise d'écoute avant d'appeler BIND (2) . .


2 commentaires

Alors .. toute autre méthode à cela? J'utilise SO_REUSEADDRDR avant les deux appels.


Le plus souvent, cette option est utilisée pour éviter d'attendre 1-2 min lors de la redémarrage du serveur d'écoute sur un port spécifique lorsqu'une prise juste fermée est dans l'état Time_wait.



2
votes

Puisque vous l'exécutez sur le même système, on dirait que vous avez une condition de course. Le client essaie de BIND () La prise juste avant que le serveur ne l'ait fermé (en supposant que le serveur et le client définissent SO_REUSeADDRR sur leurs sockets).

Vous devez mettre en œuvre une sorte de poignée de main qui permet au serveur d'informer le client après avoir fermé la prise d'écoute - peut-être que le serveur doit peut-être fermer la prise d'écoute avant de fermer la prise active du dernier jeu?


1 commentaires

Oui, il y avait un délai de 1 s avant la fermeture du socket et aucun délai lorsque j'ai essayé de le reculer. Ça marche parfaitement bien maintenant! :)



0
votes

Définition de cette option de prise permet une réutilisation de l'adresse locale. Si un problème est rencontré lorsque vous essayez de se lier à un port fermé mais non libéré (peut prendre jusqu'à 2 minutes telles que définies par Time_Wait). Appliquez l'option SO_REUSeADDRDRDDRDRDR pour libérer la ressource immédiatement et déployer l'état Time_Wait. 0 = désactive, 1 = active.

permet aux autres sockets de se lier () à ce port, sauf s'il existe déjà un support d'écoute actif au port déjà. Cela vous permet de contourner ces messages d'erreur "adresse déjà utilisée" lorsque vous essayez de redémarrer votre serveur après un crash


0 commentaires