Question

Est-il possible de désélectionner un socket après avoir appelé listen (fd, backlog)?

Edit: Mon erreur de ne pas me faire comprendre. Je voudrais être en mesure de désélectionner temporairement sur le socket. L'appel de close () laissera la socket dans l'état M2LS et m'empêchera de la rouvrir (ou pire, un programme néfaste pourrait se lier à cette socket)

Désécouter temporairement serait un moyen (peut-être pas le meilleur) de signaler à un équilibreur de charge en amont que cette application ne pouvait plus accepter de demandes pour le moment

Était-ce utile?

La solution

Certaines bibliothèques de socket vous permettent de rejeter spécifiquement les connexions entrantes. Par exemple: GNU's CommonC ++: la classe TCPsocket a un rejeter méthode.

BSD Sockets n’a pas cette fonctionnalité. Vous pouvez accepter la connexion, puis immédiatement la fermer , tout en laissant le socket ouvert:

while (running) {

  int i32ConnectFD = accept(i32SocketFD, NULL, NULL);
  while (noConnectionsPlease) {
    shutdown(i32ConnectFD, 2);
    close(i32ConnectFD);
    break;
  }

}

Autres conseils

Après la fermeture du socket, vos programmes peuvent toujours vous dire que le socket est "en cours d'utilisation", ceci est dû à une bizarrerie que je ne connais pas exactement. Mais la page de manuel relative aux sockets vous indique qu’il existe un drapeau pour réutiliser le même socket, appelé par la suite: "SO_REUSEADDR". Définissez-le à l'aide de "setsockopt ()".

Fermez-le. Si je me souviens bien,

close(fd);

En fonction de votre version modifiée de la question, je ne suis pas sûr que vous devez "désélectionner". ou fermer (). Deux options me viennent à l’esprit:

1) Une fois que vous avez appelé listen (), les connexions ne sont réellement acceptées que lorsque (assez logiquement) vous appelez accept (). Vous pouvez " ne pas écouter " en ignorant simplement l'activité du socket et en différant tous les accept () jusqu'à ce que vous soyez prêt à les utiliser. Toute connexion entrante tente d’être en retard sur la file d’attente créée lors de l’ouverture du port en mode écoute. Une fois que la file d'attente de backlog est pleine dans la pile, d'autres tentatives de connexion sont simplement abandonnées sur le sol. Lorsque vous reprenez avec accept (), vous supprimez rapidement l’arriéré et vous êtes prêt pour plus de connexions.

2) Si vous voulez vraiment que le port apparaisse complètement fermé temporairement, vous pouvez appliquer de manière dynamique le filtre de paquets au niveau du noyau au port pour empêcher les tentatives de connexion entrantes d'atteindre la pile réseau. Par exemple, vous pouvez utiliser Berkeley Packet Filter (BPF) sur la plupart des plates-formes * nix. C’est-à-dire que vous souhaitez supprimer les paquets entrants entrant dans le port d’intérêt à l’aide des fonctionnalités de pare-feu de la plate-forme. Cela varie bien sûr d’une plate-forme à l’autre, mais c’est une approche possible.

Je ne pense pas que ce soit un bon moyen de signaler un équilibreur de charge en amont. Il faudrait qu’il envoie effectivement certaines connexions à votre serveur avant que le message ne passe - ces connexions seraient probablement rejetées.

De même, toute connexion en attente lors de la fermeture du socket d'écoute sera fermée sans données.

Si vous souhaitez signaler l'équilibreur de charge en amont, vous devez disposer d'un protocole pour le faire. N'essayez pas d'abuser de TCP pour le faire.

Heureusement, si les clients sont des navigateurs Web normaux, vous pouvez vous en tirer terriblement - une simple fermeture des sockets entraîne généralement une nouvelle tentative transparente pour l'utilisateur (jusqu'à un point).

Il n’existe pas de méthode explicite pour désinscrire!

Vous pouvez soit fermer (fd) ou shutdown (fd, comment)

fd is the socket file descriptor you want to shutdown, and how is one of the following:

0 Further receives are disallowed

1 Further sends are disallowed

2 Further sends and receives are disallowed (like close())

Au niveau de base, les sockets sont ouverts ou fermés (nous allons ignorer les subtilités du diagramme d'état TCP / IP ici).

Si votre socket est fermé, rien ne peut lui envoyer de données. S'il est ouvert, les données entrantes seront acceptées et acquittées par la pile TCP / IP jusqu'à ce que son algorithme de mise en mémoire tampon crie "assez!". À ce stade, les données supplémentaires ne seront pas acquittées.

Vous avez deux choix que je peux voir. Fermez () le socket lorsque vous souhaitez "désinscrire" et le rouvrir plus tard - Utilisez setsockopt () avec l'indicateur SO_REUSEADDR pour vous permettre de vous reconnecter au port bien connu avant l'expiration de TIME_WAIT2.

L’autre choix est de garder le socket ouvert mais de ne pas en accepter () tant que vous êtes "occupé". En supposant que vous ayez un accusé de réception au niveau de l’application, vous vous rendrez compte que l’équilibreur de charge ne recevrait pas de réponse et agirait en conséquence.

Voici une approche plutôt laide basée sur votre question modifiée:

Ouvrez un socket pour écouter avec un backlog normal. Continuer.

Lorsque vous souhaitez "arrêter", ouvrez-en un deuxième avec un carnet de commandes de 1 et SO_REUSEADDR. Fermez le premier. Lorsque vous êtes prêt à reprendre, créez un autre socket avec un backlog normal.

Les détails pointilleux concernant le vidage de la file d'attente d'acceptation du socket que vous fermez seront le tueur ici. Probablement assez d'un tueur pour rendre cette approche non viable.

Je ne pense pas nécessairement que ce soit une bonne idée, mais ...

Vous pourrez peut-être appeler une seconde fois. La spécification POSIX ne dit pas non à. Vous pourriez peut-être l'appeler une seconde fois avec un paramètre de backlog de 0 lorsque vous souhaitez "désélectionner".

Que se passe-t-il quand listen est appelé avec un backlog de 0 qui semble être défini par l'implémentation? La spécification POSIX indique qu'elle peut autoriser l'acceptation de connexions, ce qui implique que certaines implémentations peuvent choisir de rejeter toutes les connexions si le paramètre de traitement en attente est 0. Il est plus probable que votre implémentation choisisse une valeur positive lorsque vous passez. en 0 (probablement 1 ou SOMAXCONN).

La question ne dit pas quel type de socket. S'il s'agit d'une prise Unix, vous pouvez arrêter et commencer à écouter avec rename (2). Vous pouvez également arrêter définitivement l'écoute avec unlink (2) et, puisque le socket reste ouvert, vous pouvez continuer à gérer votre arriéré. Cette approche semble assez pratique, bien que je n’aie pas encore utilisé et que j’explore moi-même.

Vous avez déjà obtenu des réponses sur l'impossibilité de le faire via l'API de socket.

Vous pouvez utiliser d'autres méthodes de système d'exploitation (c'est-à-dire hôte firwewall / iptables / ipfilter) pour configurer une règle de rejet temporaire.

J'ai constaté que la plupart des équilibreurs de charge sont un peu limités dans les possibilités qu'ils offrent de reconnaître les problèmes de connexion (la plupart d'entre eux reconnaissent un RST uniquement dans la sonde de connexion, et non comme une réponse à une tentative de connexion légitime.)

Quoi qu’il en soit, si vous êtes limité par les sondes détectant l’indisponibilité, vous configurez une sonde au niveau de l’application qui effectue une demande HTTP ou un login FTP, ou toute autre chose qu’elle reconnaîtra si vous fermez simplement après accept. Il pourrait même interpréter des messages d'erreur tels que "Service 500 non disponible", ce qui me semble tout de même plus clair. Avec SNMP, certains équilibreurs de charge peuvent également utiliser le résultat comme indicateur de charge.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top