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"); }
3 Réponses :
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. P>
Dans les deux cas, vous devez EM> Toujours em> Set SO_REUSeADDRDRDRDRDRDRDRDRDRDRDRDRDRDDR ne vous permet que de lier simultanément à un plus une adresse spécifique em>, c'est-à-dire le premier serveur écoute sur
inaddr_any code> (toutes les interfaces) et suivantes Les serveurs Écoutez sur différentes adresses d'interface spécifiques. P>
SO_REUSeADDRDRDRDRR CODE> SO_REUSEADDRDRDRDRR CODE> SO_REUSeADDRDRDRDRUNTRES sur la prise d'écoute avant d'appeler
BIND (2) P>. P>.
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.
Puisque vous l'exécutez sur le même système, on dirait que vous avez une condition de course. Le client essaie de 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? P> BIND () CODE> La prise juste avant que le serveur ne l'ait fermé (en supposant que le serveur et le client définissent
SO_REUSeADDRR code> sur leurs sockets). P>
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! :)
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. P>
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 p>
Veuillez afficher votre code (en particulier la pièce autour de
setSockopt () code>) 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.