J'ai l'objet tcpclient et je veux déterminer s'il est connecté ou non. J'utilise la propriété connectée de tcpclient mais elle retourne l'état de la dernière opération. donc ce n'est pas utile.
alors j'utilise ce code:
bool flag;
flag = (tcp.Client.Poll(10000, SelectMode.SelectWrite));
et
if( tcp.Client.Poll( 0, SelectMode.SelectRead ) )
{
byte[] buff = new byte[1];
if( tcp.Client.Receive( buff, SocketFlags.Peek ) == 0 )
{
flag = false;
}
}
mais cela ne fonctionne pas correctement.
Une idée?
voici mon code côté serveur:
private ArrayList _ClientList = new ArrayList();
public ClsServer(int port)
{
_TCPListener = new TcpListener(IPAddress.Any, port);
_TCPListener.Start();
Thread ListenThread = new Thread(new ThreadStart(ListenForClients));
ListenThread.IsBackground = true;
ListenThread.Start();
}
private void ListenForClients()
{
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._TCPListener.AcceptTcpClient();
client.ReceiveTimeout = 0;
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.IsBackground = true;
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
try
{
TcpClient tcpClient = (TcpClient)client;
AddObject(tcpclient);
int bytesRead;
string message = "";
byte[] RecievedPack = new byte[1024 * 1000];
NetworkStream clientStream = tcpClient.GetStream();
while (true)
{
bytesRead = 0;
try
{
////blocks until a client sends a message
bytesRead = clientStream.Read(RecievedPack, 0, RecievedPack.Length);
int Len = BitConverter.ToInt32(RecievedPack, 0);
message = UTF8Encoding.UTF8.GetString(RecievedPack, 0, Len);
}
catch (Exception er)
{
//When Client is disconnected
if (er.GetType() == typeof(IOException))
{
RemoveObject(client);
break;
}
}
//message has successfully been received
// do something
}
RemoveObject(client);
}
catch(Exception e)
{
// RemoveObject(client);
}
}
private void AddObject(object obj)
{
int totalcount, index;
totalcount = _ClientList.Count;
index = 0;
while (index < totalcount)
{
TcpClient alcobj = (TcpClient)_ClientList[index];
try
{
if (IPAddress.Equals(((IPEndPoint)alcobj.Client.RemoteEndPoint).Address,
((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address))
{
_ClientList.Remove(alcobj);
break;
}
index++;
}
catch (Exception er)
{
if (er.GetType() == typeof(ObjectDisposedException))
RemoveObject(alcobj);
}
finally
{
totalcount = _ClientList.Count;
}
}
_ClientList.Add(obj);
}
private void RemoveObject(object obj)
{
if (_ClientList.IndexOf(obj) > -1)
{
_ClientList.Remove(obj);
SendClientState(IP, false);
}
}
et voici le côté client:
public bool IsConnected
{
try
{
if (_TcpClient != null && _TcpClient.Client != null && _TcpClient.Client.Connected)
{
// Detect if client disconnected
if (_TcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_TcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
private void clsClient()
{
if(!IsConnected())
{
Connecttoserver()
}
}
private void ConnectToServer()
{
try
{
NetworkStream _NetworkStream = _TcpClient.GetStream();
byte[] _RecievedPack = new byte[1024 * 1000];
string _Message = string.Empty;
int _BytesRead;
int _Length;
while (true)
{
_BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
_Length = BitConverter.ToInt32(_RecievedPack, 0);
_Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);
if (_BytesRead != 0)
{
if (OnReceive != null)
// do something
_NetworkStream.Flush();
}
}
}
catch (Exception exp)
{
// do something
}
}
côté client, IsConnected () renvoie toujours la valeur false et tente de se connecter à serveur, de sorte que l'écouteur du serveur tente toujours d'ajouter le client dans une liste.
Utilisez ce code à la place, je l'ai testé et utilisé dans un logiciel de production réel:
public bool IsConnected
{
get
{
try
{
if (_tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected)
{
/* pear to the documentation on Poll:
* When passing SelectMode.SelectRead as a parameter to the Poll method it will return
* -either- true if Socket.Listen(Int32) has been called and a connection is pending;
* -or- true if data is available for reading;
* -or- true if the connection has been closed, reset, or terminated;
* otherwise, returns false
*/
// Detect if client disconnected
if (_tcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
}
Edit: Cependant, vous ne pouvez pas vous contenter de vérifier la connexion. Si true, procédez comme suit: renvoyant le statut de la connexion à l'exécution de cette propriété, par exemple après avoir vérifié IsConnected
et qu'il renvoie true, et pendant que vous êtes au milieu de la communication, la connexion peut être perdue là! nous l'utilisons simplement en premier lieu pour réduire la probabilité d'échec. Vous devez donc envelopper toute la communication dans un essai/attraper et vous attendre à ce que la connexion soit perdue à tout moment!
Je suggère de ne pas utiliser de telles méthodes. À mon avis, le meilleur moyen consiste à mettre en œuvre un mécanisme de maintien en vie. Toutes les X secondes, envoyez un petit message et attendez une réponse. Vous êtes probablement déconnecté lorsque: 1. Vous interceptez une exception lorsque vous essayez d'envoyer un message persistant (si vous êtes le client). 2. Vous ne recevez pas de message/réponse persistant pendant un certain temps.
Je suggère également de ne pas compter sur le TCP persistant intégré, je l'ai trouvé très peu fiable.
Mise à jour: Trouvé un message de Nice pour cette question: Poste
Le seul moyen de savoir si l'autre extrémité d'une connexion de socket est toujours connectée consiste à intercepter le résultat d'une opération de lecture ou d'écriture ou éventuellement à intercepter une exception.
Pour plus d'informations, veuillez vous référer à cette question StackOverflow: Détecter instantanément la déconnexion du client à partir du socket du serveur
Voici un petit extrait de code qui utilise simplement une Socket
en mode non bloquant et qui est connectée à un serveur.
try
{
bytesRead = nambSok.Receive(message, 4096, SocketFlags.None);
}
catch (SocketException e)
{
//a socket error has occured
switch (e.SocketErrorCode)
{
case System.Net.Sockets.SocketError.TimedOut:
case System.Net.Sockets.SocketError.WouldBlock:
if (doDisconnect == false)
{
continue;
}
break;
case System.Net.Sockets.SocketError.ConnectionReset:
case System.Net.Sockets.SocketError.ConnectionAborted:
isConnected = false;
break;
}
}
if (bytesRead > 0)
{
/* do something with data */
}
La méthode "Keep-Alive" proposée par Lior Ohana est également une excellente idée. Forcer chaque client à "enregistrer" toutes les X secondes. Le client peut détecter que le serveur est parti si une exception se produit lors de l'écriture et qu'il sait que le client est parti si un message de maintien en vie n'a pas été reçu dans un délai de X secondes.
Je suis d'accord avec Lior Ohana parce que j'ai eu ce problème avec des périphériques distants qui utilisaient une connexion GPRS Tcp. lorsque l'appareil est éteint ou déconnecté, il n'a pas alerté le serveur. Là pour j'ai utilisé ce code: j'envoie l'heure spécifique aux clients
void AnalyzeForHandShaking(Socket socketin, string Message)
{
Socket handler = socketin;
try
{
Message = Message.Trim();
if (!string.IsNullOrEmpty(Message.Trim()))
// if (Message.Equals("~"))
{
// string Serial = getSerialFromSocket(socketin).Trim();
DateTime dt = DateTime.Now;
if (handler!=null)
//if there is serial in hastable
if (!arrIPTimeHandShaking.ContainsKey(handler))
{
arrIPTimeHandShaking.Add(handler, dt);
}
else
{
arrIPTimeHandShaking[handler] = dt;
}
}
}
catch
{
}
}