Détection de la déconnexion du Client TCP
disons que j'exécute un serveur simple et que accept()
a une connexion à partir d'un client.
Quelle est la meilleure façon de savoir quand le client a déconnecté? Normalement, un client est censé envoyer une commande close, mais qu'en est-il s'il se déconnecte manuellement ou perd la connexion réseau? Comment le serveur peut-il détecter ou gérer cela?
13 réponses
select (with the read mask set) va revenir avec la poignée signalée, mais quand vous utilisez ioctl* pour vérifier le nombre d'octets en attente d'être lus, il sera zéro. C'est un signe que la prise a été déconnectée.
il s'agit d'une excellente discussion sur les différentes méthodes de vérification que le client a déconnecté: Stephen Cleary, détection de connexions à moitié ouvertes (abandonnées) .
* pour Windows utilisez ioctlsocket.
dans TCP il n'y a qu'une seule façon de détecter une déconnexion ordonnée, et c'est en obtenant zéro comme valeur de retour de read()/recv()/recvXXX()
lors de la lecture.
il n'y a qu'un seul moyen fiable de détecter une connexion rompue: en lui écrivant. Après avoir écrit assez à une connexion cassée, TCP aura fait assez de tentatives et de timeouts pour savoir qu'elle est cassée et fera éventuellement revenir write()/send()/sendXXX()
-1 avec une valeur errno/WSAGetLastError()
de ECONNRESET,
ou dans certains cas la "connection timed out". Notez que ce dernier est différent de 'connect timeout', qui peut se produire dans la phase de connexion.
vous devriez également définir un délai raisonnable de lecture, et les connexions de chute qui échouent.
la réponse ici à propos de ioctl()
et FIONREAD
est un non-sens de concurrence. Tout ce qui fait est de vous dire combien d'octets sont actuellement dans la mémoire tampon socket receive, disponible pour être lu sans blocage. Si un client ne vous envoie rien pour cinq minutes qui ne constituent pas une déconnexion, mais qui font que FIONREAD
est zéro. Pas la même chose: même pas proche.
Pour développer un peu plus:
si vous utilisez un serveur, vous devez soit utiliser TCP_KEEPALIVE pour surveiller les connexions du client, ou faire quelque chose de similaire vous-même, ou avoir connaissance des données/Protocole que vous utilisez sur la connexion.
en gros, si la connexion est désactivée (c'est-à-dire qu'elle n'est pas correctement fermée), le serveur ne remarquera rien tant qu'il n'essaiera pas d'écrire quelque chose au client, ce que le keepalive obtient pour vous. Par ailleurs, si vous connaissez mieux le protocole, vous pouvez vous déconnecter sur un temps d'inactivité de toute façon.
si vous utilisez des e/s superposées (c.-à-d. asynchrones) avec des routines d'achèvement ou des ports d'achèvement, vous serez avisé immédiatement (en supposant que vous avez une lecture en suspens) lorsque le côté client ferme la connexion.
"""
tcp_disconnect.py
Echo network data test program in python. This easily translates to C & Java.
A server program might want to confirm that a tcp client is still connected
before it sends a data. That is, detect if its connected without reading from socket.
This will demonstrate how to detect a TCP client disconnect without reading data.
The method to do this:
1) select on socket as poll (no wait)
2) if no recv data waiting, then client still connected
3) if recv data waiting, the read one char using PEEK flag
4) if PEEK data len=0, then client has disconnected, otherwise its connected.
Note, the peek flag will read data without removing it from tcp queue.
To see it in action: 0) run this program on one computer 1) from another computer,
connect via telnet port 12345, 2) type a line of data 3) wait to see it echo,
4) type another line, 5) disconnect quickly, 6) watch the program will detect the
disconnect and exit.
John Masinter, 17-Dec-2008
"""
import socket
import time
import select
HOST = '' # all local interfaces
PORT = 12345 # port to listen
# listen for new TCP connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
# accept new conneciton
conn, addr = s.accept()
print 'Connected by', addr
# loop reading/echoing, until client disconnects
try:
conn.send("Send me data, and I will echo it back after a short delay.\n")
while 1:
data = conn.recv(1024) # recv all data queued
if not data: break # client disconnected
time.sleep(3) # simulate time consuming work
# below will detect if client disconnects during sleep
r, w, e = select.select([conn], [], [], 0) # more data waiting?
print "select: r=%s w=%s e=%s" % (r,w,e) # debug output to command line
if r: # yes, data avail to read.
t = conn.recv(1024, socket.MSG_PEEK) # read without remove from queue
print "peek: len=%d, data=%s" % (len(t),t) # debug output
if len(t)==0: # length of data peeked 0?
print "Client disconnected." # client disconnected
break # quit program
conn.send("-->"+data) # echo only if still connected
finally:
conn.close()
Try looking for EPOLLHUP or EPOLLERR. Comment puis-je vérifier que la connexion client est toujours vivante
lire et chercher 0 fonctionne dans certains cas, mais pas tous.
TCP a des procédures" ouvertes "et" fermées " dans le protocole. Une fois" ouverte", une connexion est maintenue jusqu'à"fermée". Mais il ya beaucoup de choses qui peuvent arrêter le flux de données anormalement. Cela étant dit, les techniques pour déterminer s'il est possible d'utiliser un lien sont très dépendantes des couches logicielles entre le protocole et le programme d'application. Ceux mentionnés ci-dessus se concentrent sur un programmeur essayant d'utiliser une socket d'une manière non invasive (lire ou écrire 0 bytes) sont peut-être le plus commun. Certains calques dans les bibliothèques fourniront le" polling " pour un programmeur. Par exemple, les appels Win32 asych (retardés) peuvent démarrer une lecture qui reviendra sans erreur et 0 octets pour signaler une socket qui ne peut plus être lue (probablement une procédure TCP FIN). D'autres environnements peuvent utiliser des "événements" tels que définis dans leurs couches d'enrubannage. Il n'y a pas de réponse unique à cette question. Le mécanisme pour détecter quand une socket ne peut pas être utilisé et doit être fermé dépend des enveloppes fourni dans les bibliothèques. Il est également intéressant de noter que les sockets eux-mêmes peuvent être réutilisés par des couches sous une bibliothèque d'applications, il est donc sage de comprendre comment votre environnement traite L'interface des Sockets de Berkley.
la valeur de retour de receive sera -1 si la connexion est perdue sinon ce sera la taille du tampon.
void ReceiveStream(void *threadid)
{
while(true)
{
while(ch==0)
{
char buffer[1024];
int newData;
newData = recv(thisSocket, buffer, sizeof(buffer), 0);
if(newData>=0)
{
std::cout << buffer << std::endl;
}
else
{
std::cout << "Client disconnected" << std::endl;
if (thisSocket)
{
#ifdef WIN32
closesocket(thisSocket);
WSACleanup();
#endif
#ifdef LINUX
close(thisSocket);
#endif
}
break;
}
}
ch = 1;
StartSocket();
}
}
apr du projet apache est une bonne référence pour ce problème. Il utilise poll avec une valeur de timeout pour vérifier si la connexion de l'autre côté est cassée ou non.
j'ai essayé quelques solutions mais celle-ci semble fonctionner le mieux pour détecter la déconnexion de l'hôte et/ou du client dans Windows. Il est pour les sockets non-bloquants, et dérivé de exemple D'IBM .
char buf;
int length=recv(socket, &buf, 0, 0);
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0){
return 0;
}
if (nError==0){
if (length==0) return 0;
}
Il est vraiment facile à faire: fiable et pas salissant:
Try Clients.Client.Send(BufferByte) Catch verror As Exception BufferString = verror.ToString End Try If BufferString <> "" Then EventLog.Text &= "User disconnected: " + vbNewLine Clients.Close() End If
nous exécutons dans la même question lors de la détection du retrait du câble sur le PC était le problème. Après googling, nous avons cliqué sur la bibliothèque SuperCom pour TCP qui offrait cette fonctionnalité et une bibliothèque de communication de données très fiable qui pouvait également gérer les événements de rapport quand une connexion était fermée.
cette question Est fondée sur diverses idées fausses au sujet de la pile réseau.
tout d'abord, il n'y a pas de concept de 'connexion' Tcp ou autre et plus tôt vous ferez cette distinction plus tôt vous vous rendrez compte que ce n'est pas différent de udp ou de tout autre protocole.
lorsque votre temps de réception hors soit vous avez des données à envoyer ou vous ne le faites pas.
Si vous ne voulez pas transmettre que, éventuellement augmenter le délai d'attente et recevoir de nouveau.
Si le client débranché de l'ordinateur ou autrement déconnecté alors comment ou pourquoi cette question?
Est-ce que va briser votre "connexion"? Peut-être, mais peut-être pas, qui sait comment votre machine est mise en place ou le LSP de tels.
la façon normale de faire ceci est exactement comme avec tous les autres protocoles et je vous rappelle que la socket est déjà 'connectée' dans les cas où une recive se produit.
quand vous essayez d'Envoyer à ce client quelque chose que vous saurez si le client est "connecté" ou plus correctement reconnu vos données sous Tcp. (Sous udp également en fonction du réseau via icmp)
la raison pour laquelle vous avez voté cette réponse est à cause de votre propre malentendu.
en bref, si vous avez des données pour envoyer l'envoyer et de déterminer quelle action est nécessaire après l'envoi réussi ou échoué.
si votre temps d'opération de réception la même chose s'applique et vous pouvez éventuellement utiliser une taille 0 Envoyer pour confirmer que l'autre partie reçoit toujours vos données.