Comment configurer le délai de connexion de socket

Lorsque le client essaie de se connecter à une adresse IP déconnectée, le délai d’attente est supérieur à 15 secondes … Comment réduire ce délai? Quelle est la méthode pour le configurer?

Le code que j’utilise pour configurer une connexion de socket est le suivant:

try { m_clientSocket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(serverIp); int iPortNo = System.Convert.ToInt16(serverPort); IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo); m_clientSocket.Connect(ipEnd); if (m_clientSocket.Connected) { lb_connectStatus.Text = "Connection Established"; WaitForServerData(); } } catch (SocketException se) { lb_connectStatus.Text = "Connection Failed"; MessageBox.Show(se.Message); } 

J’ai trouvé ça. Plus simple que la réponse acceptée et fonctionne avec .NET v2

 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Connect using a timeout (5 seconds) IAsyncResult result = socket.BeginConnect( sIP, iPort, null, null ); bool success = result.AsyncWaitHandle.WaitOne( 5000, true ); if ( socket.Connected ) { socket.EndConnect( result ); } else { // NOTE, MUST CLOSE THE SOCKET socket.Close(); throw new ApplicationException("Failed to connect server."); } //... 

Ma prise:

 public static class SocketExtensions { ///  /// Connects the specified socket. ///  /// The socket. /// The IP endpoint. /// The timeout. public static void Connect(this Socket socket, EndPoint endpoint, TimeSpan timeout) { var result = socket.BeginConnect(endpoint, null, null); bool success = result.AsyncWaitHandle.WaitOne(timeout, true); if (success) { socket.EndConnect(result); } else { socket.Close(); throw new SocketException(10060); // Connection timed out. } } } 

Je viens d’écrire une classe d’extension afin d’autoriser les délais d’attente dans les connexions. Utilisez-le exactement comme vous utiliseriez les méthodes standard Connect() , avec un paramètre supplémentaire nommé timeout .

 using System; using System.Net; using System.Net.Sockets; ///  /// Extensions to Socket class ///  public static class SocketExtensions { ///  /// Connects the specified socket. ///  /// The socket. /// The host. /// The port. /// The timeout. public static void Connect(this Socket socket, ssortingng host, int port, TimeSpan timeout) { AsyncConnect(socket, (s, a, o) => s.BeginConnect(host, port, a, o), timeout); } ///  /// Connects the specified socket. ///  /// The socket. /// The addresses. /// The port. /// The timeout. public static void Connect(this Socket socket, IPAddress[] addresses, int port, TimeSpan timeout) { AsyncConnect(socket, (s, a, o) => s.BeginConnect(addresses, port, a, o), timeout); } ///  /// Asyncs the connect. ///  /// The socket. /// The connect. /// The timeout. private static void AsyncConnect(Socket socket, Func connect, TimeSpan timeout) { var asyncResult = connect(socket, null, null); if (!asyncResult.AsyncWaitHandle.WaitOne(timeout)) { try { socket.EndConnect(asyncResult); } catch (SocketException) { } catch (ObjectDisposedException) { } } } 

Je ne programme pas en C # mais en C, nous résolvons le même problème en rendant le socket non-bloquant et en plaçant ensuite la fd dans une boucle select / poll avec une valeur de timeout égale au temps que nous sums prêts à attendre pour la connexion réussir.

Je l’ai trouvé pour Visual C ++ et l’explication qu’il contient se plie également au mécanisme de sélection / interrogation que j’ai expliqué précédemment.

D’après mon expérience, vous ne pouvez pas modifier les valeurs de délai de connexion par socket. Vous le changez pour tous (en réglant les parameters du système d’exploitation).

J’ai résolu le problème en utilisant la méthode Socket.ConnectAsync au lieu de la méthode Socket.Connect. Après avoir appelé Socket.ConnectAsync (SocketAsyncEventArgs), démarrez une timer (timer_connection), si le temps est écoulé, vérifiez si la connexion de socket est connectée (if (m_clientSocket.Connected)), sinon, une erreur de délai d’attente apparaît.

 private void connect(ssortingng ipAdd,ssortingng port) { try { SocketAsyncEventArgs e=new SocketAsyncEventArgs(); m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(serverIp); int iPortNo = System.Convert.ToInt16(serverPort); IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo); //m_clientSocket. e.RemoteEndPoint = ipEnd; e.UserToken = m_clientSocket; e.Completed+=new EventHandler(e_Completed); m_clientSocket.ConnectAsync(e); if (timer_connection != null) { timer_connection.Dispose(); } else { timer_connection = new Timer(); } timer_connection.Interval = 2000; timer_connection.Tick+=new EventHandler(timer_connection_Tick); timer_connection.Start(); } catch (SocketException se) { lb_connectStatus.Text = "Connection Failed"; MessageBox.Show(se.Message); } } private void e_Completed(object sender,SocketAsyncEventArgs e) { lb_connectStatus.Text = "Connection Established"; WaitForServerData(); } private void timer_connection_Tick(object sender, EventArgs e) { if (!m_clientSocket.Connected) { MessageBox.Show("Connection Timeout"); //m_clientSocket = null; timer_connection.Stop(); } } 

Vérifiez ceci sur MSDN . Il ne semble pas que vous puissiez faire cela avec les propriétés implémentées dans la classe Socket.

L’affiche sur MSDN a en fait résolu son problème en utilisant le threading. Il avait un thread principal qui appelait les autres threads qui exécutaient le code de connexion pendant quelques secondes, puis vérifiait la propriété Connected du socket:

J’ai créé une autre méthode qui a effectivement connecté la socket … si le thread principal dormait pendant 2 secondes, puis vérifier la méthode de connexion (qui est exécutée dans un thread séparé) si la socket était connectée bien sinon lancer une exception “Timed out” et c’est tout. Merci encore pour les repleies.

Qu’est-ce que vous essayez de faire et pourquoi ne peut-il pas attendre 15 à 30 secondes avant la fin du temps imparti?

J’ai eu le même problème lors de la connexion à un socket et je suis venu avec la solution ci-dessous, il fonctionne bien pour moi. `

 private bool CheckConnectivityForProxyHost(ssortingng hostName, int port) { if (ssortingng.IsNullOrEmpty(hostName)) return false; bool isUp = false; Socket testSocket = null; try { testSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = null; if (testSocket != null && NetworkingCollaboratorBase.GetResolvedConnecionIPAddress(hostName, out ip))//Use a method to resolve your IP { IPEndPoint ipEndPoint = new IPEndPoint(ip, port); isUp = false; //time out 5 Sec CallWithTimeout(ConnectToProxyServers, 5000, testSocket, ipEndPoint); if (testSocket != null && testSocket.Connected) { isUp = true; } } } } catch (Exception ex) { isUp = false; } finally { try { if (testSocket != null) { testSocket.Shutdown(SocketShutdown.Both); } } catch (Exception ex) { } finally { if (testSocket != null) testSocket.Close(); } } return isUp; } private void CallWithTimeout(Action action, int timeoutMilliseconds, Socket socket, IPEndPoint ipendPoint) { try { Action wrappedAction = () => { action(socket, ipendPoint); }; IAsyncResult result = wrappedAction.BeginInvoke(null, null); if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds)) { wrappedAction.EndInvoke(result); } } catch (Exception ex) { } } private void ConnectToProxyServers(Socket testSocket, IPEndPoint ipEndPoint) { try { if (testSocket == null || ipEndPoint == null) return; testSocket.Connect(ipEndPoint); } catch (Exception ex) { } } 

J’ai travaillé avec Unity et j’ai rencontré des problèmes avec BeginConnect et d’autres méthodes asynchrones depuis socket.

Il y a quelque chose que je ne comprends pas mais les exemples de code précédents ne fonctionnent pas pour moi.

J’ai donc écrit ce morceau de code pour le faire fonctionner. Je le teste sur un réseau adhoc avec Android et PC, également en local sur mon ordinateur. J’espère que ça peut aider.

 using System.Net.Sockets; using System.Threading; using System.Net; using System; using System.Diagnostics; class ConnexionParameter : Guardian { public TcpClient client; public ssortingng address; public int port; public Thread principale; public Thread thisthread = null; public int timeout; private EventWaitHandle wh = new AutoResetEvent(false); public ConnexionParameter(TcpClient client, ssortingng address, int port, int timeout, Thread principale) { this.client = client; this.address = address; this.port = port; this.principale = principale; this.timeout = timeout; thisthread = new Thread(Connect); } public void Connect() { WatchDog.Start(timeout, this); try { client.Connect(IPAddress.Parse(address), port); } catch (Exception) { UnityEngine.Debug.LogWarning("Unable to connect service (Training mode? Or not running?)"); } OnTimeOver(); //principale.Resume(); } public bool IsConnected = true; public void OnTimeOver() { try { if (!client.Connected) { /*there is the sortingck. The abort method from thread doesn't make the connection stop immediately(I think it's because it rise an exception that make time to stop). Instead I close the socket while it's trying to connect , that make the connection method return faster*/ IsConnected = false; client.Close(); } wh.Set(); } catch(Exception) { UnityEngine.Debug.LogWarning("Connexion already closed, or forcing connexion thread to end. Ignore."); } } public void Start() { thisthread.Start(); wh.WaitOne(); //principale.Suspend(); } public bool Get() { Start(); return IsConnected; } } public static class Connexion { public static bool Connect(this TcpClient client, ssortingng address, int port, int timeout) { ConnexionParameter cp = new ConnexionParameter(client, address, port, timeout, Thread.CurrentThread); return cp.Get(); } //http://stackoverflow.com/questions/19653588/timeout-at-acceptsocket public static Socket AcceptSocket(this TcpListener tcpListener, int timeoutms, int pollInterval = 10) { TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutms); var stopWatch = new Stopwatch(); stopWatch.Start(); while (stopWatch.Elapsed < timeout) { if (tcpListener.Pending()) return tcpListener.AcceptSocket(); Thread.Sleep(pollInterval); } return null; } } 

et il existe un chien de garde très simple sur C # pour le faire fonctionner:

 using System.Threading; public interface Guardian { void OnTimeOver(); } public class WatchDog { int m_iMs; Guardian m_guardian; public WatchDog(int a_iMs, Guardian a_guardian) { m_iMs = a_iMs; m_guardian = a_guardian; Thread thread = new Thread(body); thread.Start(this); } private void body(object o) { WatchDog watchdog = (WatchDog)o; Thread.Sleep(watchdog.m_iMs); watchdog.m_guardian.OnTimeOver(); } public static void Start(int a_iMs, Guardian a_guardian) { new WatchDog(a_iMs, a_guardian); } } 

C’est comme la réponse de FlappySock, mais j’ai ajouté un rappel parce que je n’aimais pas la mise en page et comment le booléen était renvoyé. Dans les commentaires de cette réponse de Nick Miller:

D’après mon expérience, si le point d’extrémité peut être atteint, mais qu’il n’y a pas de serveur sur le point d’extrémité capable de recevoir la connexion, alors AsyncWaitHandle.WaitOne sera signalé, mais le socket restra déconnecté.

Donc, pour moi, cela semble dangereux car je préfère utiliser socket.Connected . Je mets un booléen nullable et le mets à jour dans la fonction de rappel. J’ai également constaté qu’il ne finissait pas toujours de rapporter le résultat avant de retourner à la fonction principale – je le gère aussi, et le fait attendre le résultat en utilisant le délai d’attente:

 private static bool? areWeConnected = null; private static bool checkSocket(ssortingng svrAddress, int port) { IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(svrAddress), port); Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); int timeout = 5000; // int.Parse(ConfigurationManager.AppSettings["socketTimeout"].ToSsortingng()); int ctr = 0; IAsyncResult ar = socket.BeginConnect(endPoint, Connect_Callback, socket); ar.AsyncWaitHandle.WaitOne( timeout, true ); // Sometimes it returns here as null before it's done checking the connection // No idea why, since .WaitOne() should block that, but it does happen while (areWeConnected == null && ctr < timeout) { Thread.Sleep(100); ctr += 100; } // Given 100ms between checks, it allows 50 checks // for a 5 second timeout before we give up and return false, below if (areWeConnected == true) { return true; } else { return false; } } private static void Connect_Callback(IAsyncResult ar) { areWeConnected = null; try { Socket socket = (Socket)ar.AsyncState; areWeConnected = socket.Connected; socket.EndConnect(ar); } catch (Exception ex) { areWeConnected = false; // log exception } } 

Related: Comment vérifier si je suis connecté?

Il devrait y avoir une propriété ReceiveTimeout dans la classe Socket.

Propriété Socket.ReceiveTimeout