La préoccupation de la manipulation de mauvais appel à accept()
-
13-11-2019 - |
Question
Je suis en train d'écrire un La BOUE serveur à des fins personnelles à des fins de formation et j'ai heureusement réussi à envelopper le support des choses dans un couple de classes et tout semble fonctionner correctement;le serveur écoute et accepte les connexions et pour l'instant, prend le texte à partir du client et l'envoie à l'arrière droit.
Le truc c'est que je ne suis pas tout à fait sûr de quoi faire avec un appel à accept() qui renvoie autre chose que WSAEWOULDBLOCK ou un socket valide.Dois-je simplement réinitialiser le nouveau socket 0 et retour, avec peut-être un message d'erreur en disant quelque chose de mauvais s'est passé?C'est ce que je suis en train de faire maintenant, avec l'ajout d', si cela se passe 20 fois, je vais arrêter le serveur.
void MUDControlSocket::Poll()
{
// create a new connection here
timeval timeout;
FD_ZERO(&ReadSet);
FD_ZERO(&WriteSet);
FD_ZERO(&ExceptionSet);
TopSocket = GetSocket();
NewSocket = 0;
FD_SET( GetSocket(), &ReadSet );
if( SocketList.size() > 0 )
{
for( sockIter iter = SocketList.begin(); iter != SocketList.end(); ++iter )
{
FD_SET((*iter)->GetSocket(), &ReadSet);
FD_SET((*iter)->GetSocket(), &WriteSet);
FD_SET((*iter)->GetSocket(), &ExceptionSet);
TopSocket = (*iter)->GetSocket();
}
}
if( select( TopSocket+1, &ReadSet, &WriteSet, &ExceptionSet, &timeout ) == SOCKET_ERROR )
{
cout << "Error on select() call: " << SocketErrorType(WSAGetLastError()) << endl;
delete this;
exit(EXIT_FAILURE);
}
// as long as everything is working correctly, this if block should always be entered UNLESS a new connection is accepted
if( (NewSocket = accept(GetSocket(), NULL, NULL) ) == INVALID_SOCKET )
{
if( WSAGetLastError() == WSAEWOULDBLOCK ) // it's not an actual problem. just nothing to connect to yet
return;
NewSocket = 0;
static int count = 0;
cout << "Error on accepting new connection: " << SocketErrorType(WSAGetLastError()) << endl;
if( ++count >= 20 )
done = true;
return;
}
SocketList.push_back(new MUDSocket(NewSocket)); // only happens if accept DOES NOT return a value of INVALID_SOCKET i.e. a new connection was accepted
TopSocket = NewSocket;
NewSocket = 0;
}
TopSocket et NewSocket sont de type SOCKET et a déclaré à la portée de fichier.SocketList est un std::liste des MUDSocket* et MUDControlSocket est dérivé de MUDSocket comme un singleton.
Laissez-moi savoir si vous avez besoin de plus d'info et merci pour toute aide.
La solution
D'abord:ne réglez pas le socket à 0:c'est une bonne fd pour les sockets sur certains systèmes *NIX, et une mauvaise habitude à prendre.Supposons le seul socket non valide fd est -1.Faire quelque chose d'autre vous donne un vrai bugs dans le réel logiciel de la suite (faites-moi confiance:Je parle de l'expérience de débogage de code utilisé 0 non valide prise fd).
Autre que cela, je dirais juste soulever une exception: accept
ne devrait pas échouer, à moins que vous manquez de ressources, qui devraient être à la fois exceptionnel et une erreur.C++ dispose d'un mécanisme pour le traitement de telles choses, et que des exceptions.
BTW: delete this
est presque toujours une très mauvaise idée, de sortir dans le milieu de votre code peut rendre difficile à déboguer (lever une exception en place) et l'appelant de ne le sortir en cas de besoin) et au lieu d'essayer d'accepter une prise avec accept
vous pouvez utiliser select
pour vous dire qu'il n'y a rien à accepter - et déplacez le cas de la manipulation de la fonction à sélectionner uniquement là.Vous pourriez aller un peu plus loin et de mettre en œuvre une spécialisée modèle observateur (comme je l'ai fait sur mon podcast il y a un mois) à la pratique n'est pas seulement votre code de mise en réseau, mais vos modèles de conception ainsi.Ce serait aussi aider à rendre votre code plus portable, et ré-utilisables plus tard.
HTH
Autres conseils
Renvoie l'erreur et laissez le code d'appel qui le traite de manière appropriée.
Certaines des autres erreurs possible d'accepter sont que la mémoire est faible, le nombre de connexions est épuisé, etc., etc.
Peut-être peut-être peut-être être géré en fermant des connexions inutilisées ou oubliées, ou simplement abandonner et jeter une exception.