web-dev-qa-db-fra.com

Comment trouver l'état de connexion du socket en C?

J'ai une connexion TCP. Le serveur lit simplement les données du client. Maintenant, si la connexion est perdue, le client obtiendra une erreur lors de l'écriture des données dans le tuyau (tuyau cassé), mais le serveur écoute toujours sur ce canal. Existe-t-il un moyen de savoir si la connexion est UP ou NON?

25
Blacklabel

Vous pouvez appeler getsockopt comme suit:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);

Pour tester si le socket est en place:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}
33
Simone

La seule façon de détecter de manière fiable si un socket est toujours connecté est d'essayer périodiquement d'envoyer des données. Il est généralement plus pratique de définir un paquet "ping" au niveau de l'application que les clients ignorent, mais si le protocole est déjà spécifié sans une telle capacité, vous devriez être en mesure de configurer les sockets tcp pour ce faire en définissant SO_KEEPALIVE option de socket. J'ai lié à la documentation winsock, mais la même fonctionnalité devrait être disponible sur toutes les piles de socket de type BSD.

11
Chris Becke

L'option de socket TCP keepalive (SO_KEEPALIVE) aiderait dans ce scénario et fermerait le socket serveur en cas de perte de connexion.

4
blaze

J'avais un problème similaire. Je voulais savoir si le serveur est connecté au client ou si le client est connecté au serveur. Dans de telles circonstances, la valeur de retour de la fonction recv peut être utile. Si le socket n'est pas connecté, il retournera 0 octet. Ainsi, en utilisant cela, j'ai rompu la boucle et je n'ai pas eu à utiliser de threads de fonctions supplémentaires. Vous pouvez également utiliser la même chose si les experts estiment que c'est la bonne méthode.

2
Parth Shah

Vous devriez essayer d'utiliser: getpeername la fonction.

maintenant, lorsque la connexion est coupée, vous obtiendrez errno: ENOTCONN - La prise n'est pas connectée. ce qui signifie pour vous DOWN.

sinon (si aucun autre échec), le code retour sera 0 -> ce qui signifie UP.

ressources: page de manuel: http://man7.org/linux/man-pages/man2/getpeername.2.html =

1
Tal Bar

get sock opt peut être quelque peu utile, cependant, une autre façon serait d'installer un gestionnaire de signal pour SIGPIPE. Fondamentalement, chaque fois que la connexion socket est interrompue, le noyau envoie un signal SIGPIPE au processus et vous pouvez alors faire le nécessaire. Mais cela ne fournit toujours pas la solution pour connaître l'état de la connexion. J'espère que cela t'aides.

1
chandank

Il existe un moyen simple de vérifier l'état de la connexion de socket via l'appel poll. Tout d'abord, vous devez interroger le socket, qu'il ait un événement POLLIN.

  1. Si le socket n'est pas fermé et qu'il y a des données à lire, read renverra plus de zéro.
  2. S'il n'y a pas de nouvelles données sur le socket, alors POLLIN sera mis à 0 dans revents
  3. Si le socket est fermé, l'indicateur POLLIN sera mis à un et read renverra 0.

Voici un petit extrait de code:

int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s1");
    abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s2");
    abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024]; 
while (true)
{
    poll(pfd,2,5);
    if (pfd[0].revents & POLLIN)
    {
        int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_2, sock_buf, sock_readden);
    }
    if (pfd[1].revents & POLLIN)
    {
        int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_1, sock_buf, sock_readden);
    }
}
1
yanpas