c# détection de déconnexion tcp
J'ai deux applications simples:
-
Une application Serveur qui attend sur un port tcp spécifique pour un client pour se connecter. Puis à l'écoute de ce qu'il dit, envoyer des commentaires et DÉCONNECTEZ le client.
-
Un Formulaire de demande qui se connecte au serveur de l'application, puis dit quelque chose, puis d'attendre pour les commentaires et les déconnecter du serveur, puis cliquez sur afficher les commentaires dans le formulaire.
Si l'application serveur semble se comporter correctement (je l'ai testé avec Telnet et je vois les commentaires et je vois que la déconnexion se produisent directement après les commentaires), le formulaire de demande cependant ne semble pas à l'avis de la déconnecter du serveur. ( TcpClient.Connecté semble rester fidèle, même après que le serveur est déconnecté )
Ma question est: pourquoi est-TcpClient.Connecté rester vrai et comment puis-je savoir si/quand le serveur est déconnecté?
Voici mon code complet:
Formulaire de demande:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace Sender
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void sendButton_Click(object sender, EventArgs e)
{
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 81);
responseLabel.Text = "waiting for response...";
responseLabel.Invalidate();
//write request
NetworkStream networkStream = tcpClient.GetStream();
byte[] buffer = (new ASCIIEncoding()).GetBytes("Hello World! ");
networkStream.Write(buffer, 0, buffer.Length);
networkStream.Flush();
//read response
Thread readThread = new Thread(new ParameterizedThreadStart(ReadResponse));
readThread.Start(tcpClient);
}
void ReadResponse(object arg)
{
TcpClient tcpClient = (TcpClient)arg;
StringBuilder stringBuilder = new StringBuilder();
NetworkStream networkStream = tcpClient.GetStream();
bool timeout = false;
DateTime lastActivity = DateTime.Now;
while (tcpClient.Connected && !timeout)
{
if (networkStream.DataAvailable)
{
lastActivity = DateTime.Now;
while (networkStream.DataAvailable)
{
byte[] incomingBuffer = new byte[1024];
networkStream.Read(incomingBuffer, 0, 1024);
char[] receivedChars = new char[1024];
(new ASCIIEncoding()).GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0);
stringBuilder.Append(receivedChars);
}
}
else
{
if (DateTime.Now > lastActivity.AddSeconds(60))
timeout = true;
}
System.Threading.Thread.Sleep(50);
}
Invoke((MethodInvoker)delegate
{
responseLabel.Text = "Response from Listener:\n" + stringBuilder.ToString();
responseLabel.Invalidate();
});
if (timeout)
{
Console.Write("A timeout occured\n");
networkStream.Close();
tcpClient.Close();
}
}
}
}
L'application serveur:
using System.Net;
using System.Net.Sockets;
using System.Text;
using System;
using System.Threading;
namespace Listener
{
class Program
{
static void Main(string[] args)
{
var tcpListener = new TcpListener(IPAddress.Any, 81);
tcpListener.Start();
Thread clientThread = new Thread(new ParameterizedThreadStart(Listen));
clientThread.Start(tcpListener);
}
static void Listen(object arg)
{
TcpListener tcpListener = (TcpListener)arg;
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
clientThread.Start(tcpClient);
}
}
static void HandleClient(object arg)
{
TcpClient tcpClient = (TcpClient)arg;
StringBuilder stringBuilder = new StringBuilder();
ASCIIEncoding encoder = new ASCIIEncoding();
DateTime lastActivity = DateTime.Now;
//read request
NetworkStream networkStream = tcpClient.GetStream();
int timeout = 5; //gives client some time to send data after connecting
while (DateTime.Now < lastActivity.AddSeconds(timeout) && stringBuilder.Length==0)
{
if (!networkStream.DataAvailable)
{
System.Threading.Thread.Sleep(50);
}
else
{
while (networkStream.DataAvailable)
{
lastActivity = DateTime.Now;
byte[] incomingBuffer = new byte[1024];
networkStream.Read(incomingBuffer, 0, 1024);
char[] receivedChars = new char[1024];
encoder.GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0);
stringBuilder.Append(receivedChars);
}
}
}
string request = stringBuilder.ToString();
//write response
string response = "The listener just received: " + request;
byte[] outgoingBuffer = encoder.GetBytes(response);
networkStream.Write(outgoingBuffer, 0, outgoingBuffer.Length);
networkStream.Flush();
networkStream.Close();
tcpClient.Close();
}
}
}
OriginalL'auteur nl-x | 2013-02-25
Vous devez vous connecter pour publier un commentaire.
TcpClient /NetworkStream n'a pas notifié lorsque la connexion est fermée.
La seule option disponible pour vous est d'attraper les exceptions lors de l'écriture dans le flux.
Y A quelques années, nous nous sommes déplacés à l'aide de sockets au lieu de tcp client. socket est plus utilisable que par rapport à tcpclient.
il ya un couple de méthodes que vous pouvez utiliser
Sondage est l'un d'entre eux
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll.aspx
Vous pouvez également faire une vérification sur le résultat de l'Écrire lui-même. il vous donne le nombre d'octets effectivement écrits.
La propriété Connected lui-même ne fait que refléter l'état lors de la dernière opération. Ses états de documentation "La valeur de la propriété Connected reflète l'état de la connexion la plus récente opération. Si vous avez besoin de déterminer l'état actuel de la connexion, effectuer un non-blocage, de zéro octet Envoyer l'appel. Si les retours d'appel avec succès ou jette un WAEWOULDBLOCK code d'erreur (10035), puis le socket est toujours connecté, sinon, le support n'est plus connecté."
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx
Juste pour être très clair: c#/.NET ne me souviens pas si le parti connecté a gracieusement déconnecté? Il interroge la connexion de savoir si la connexion est interrompue, même si le parti connecté a gracieusement déconnecté plus tôt?
Réponse acceptée. Bien que je n'ai toujours pas entièrement d'accord. Le RFC tools.ietf.org/html/rfc793#page-38 (cas 2) indique que l'utilisateur (application?) sera dit une FIN (débranchez l'annonce a bien été reçu. Cette élémentaires bits de données DOIT être présent quelque part dans .NET...
Ouais, j'ai lu que trop. C'est presque le même comme vous l'avez suggéré plus tôt. Si comme pour mon précédent commentaire: je ne comprends vraiment pas pourquoi .NET serait tout simplement pas garder une trace de gracieux tcp débranchez l'état. Si l'autre partie annonce qu'il va déconnecter, puis il y a au moins doit être un événement pour cela.
if (tcpClient.Client.Sondage(1, SelectMode.SelectRead) && !networkStream.DataAvailable) { // Vérifie si la connexion est fermée: Lors de l'utilisation de SelectRead, Poll() renvoie true si et seulement si: (1) Nous sommes à l'écoute, qui ne nous sont pas. (2) de Nouvelles données sont disponibles; nous avons donc vérifier networkStream.DataAvailable APRÈS l'appel de Poll(), car il pourrait changer au cours de Poll() (3) La connexion est en effet fermé. }
OriginalL'auteur Hermit Dave
Cette propriété n'est pas de vous informer si la socket est fermée sur le côté serveur.
Dans votre situation, vous pouvez soit mettre en œuvre un "keepalive" fonction d'où vous sondage la connexion toutes les t minutes/secondes, ou ajouter beaucoup de try/captures à chaque fois que vous essayez de lire ou d'écrire dans le socket. Lorsque j'utilise TCP, je viens de comprendre un Reconnect() méthode qui va dans chaque instruction catch.
OriginalL'auteur chrisevett