Как настроить тайм-аут подключения сокета
когда клиент пытается подключиться к отключенному IP-адресу, существует длительный тайм-аут более 15 секунд... Как мы можем уменьшить этот таймаут? Каков способ его настройки?
код, который я использую для настройки подключения сокета, выглядит следующим образом:
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);
}
10 ответов:
Я нашел это. Проще, чем принятый ответ, и работает с .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."); } //...
мое мнение:
public static class SocketExtensions { /// <summary> /// Connects the specified socket. /// </summary> /// <param name="socket">The socket.</param> /// <param name="endpoint">The IP endpoint.</param> /// <param name="timeout">The timeout.</param> 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. } } }
Я просто написал класс расширения, чтобы разрешить тайм-ауты в соединениях. Используйте его точно так же, как вы бы использовали стандартный
Connect()методы, с дополнительным параметром с именемtimeout.using System; using System.Net; using System.Net.Sockets; /// <summary> /// Extensions to Socket class /// </summary> public static class SocketExtensions { /// <summary> /// Connects the specified socket. /// </summary> /// <param name="socket">The socket.</param> /// <param name="host">The host.</param> /// <param name="port">The port.</param> /// <param name="timeout">The timeout.</param> public static void Connect(this Socket socket, string host, int port, TimeSpan timeout) { AsyncConnect(socket, (s, a, o) => s.BeginConnect(host, port, a, o), timeout); } /// <summary> /// Connects the specified socket. /// </summary> /// <param name="socket">The socket.</param> /// <param name="addresses">The addresses.</param> /// <param name="port">The port.</param> /// <param name="timeout">The timeout.</param> 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); } /// <summary> /// Asyncs the connect. /// </summary> /// <param name="socket">The socket.</param> /// <param name="connect">The connect.</param> /// <param name="timeout">The timeout.</param> private static void AsyncConnect(Socket socket, Func<Socket, AsyncCallback, object, IAsyncResult> connect, TimeSpan timeout) { var asyncResult = connect(socket, null, null); if (!asyncResult.AsyncWaitHandle.WaitOne(timeout)) { try { socket.EndConnect(asyncResult); } catch (SocketException) { } catch (ObjectDisposedException) { } } }
Я не программирую на C#, но в C мы решаем ту же проблему, делая сокет неблокирующим, а затем помещая fd в цикл select/poll со значением тайм-аута, равным количеству времени, которое мы готовы ждать успешного подключения.
нашел этой для Visual C++ и объяснение там также склоняется к механизму выбора / опроса, который я объяснил ранее.
по моему опыту, вы не можете изменить значения времени ожидания подключения в розетку. Изменения это для всех (путем настройки параметров ОС).
Я решил проблему с помощью сокетов.Метод ConnectAsync вместо сокета.метод Connect. После вызова сокета.ConnectAsync (SocketAsyncEventArgs), запустите таймер (timer_connection), если время истекло, проверьте, подключено ли соединение сокета(if (m_clientSocket.Подключен)), если нет, всплывает ошибка тайм-аута.
private void connect(string ipAdd,string 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<SocketAsyncEventArgs>(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(); } }
проверьте это на MSDN. Не похоже, что вы можете сделать это с помощью реализованных свойств в классе сокета.
Плакат на MSDN на самом деле решил свою проблему С помощью резьбы. У него был основной поток, который вызывал другие потоки, которые запускали код соединения в течение нескольких секунд, а затем проверяли свойство Connected сокета:Я создал другой метод, который на самом деле подключил розетку ... было главное нить сна в течение 2 секунд, а затем проверьте способ подключения (который выполняется в отдельном потоке), если розетка была подключена хорошо в противном случае исключение "тайм-аут" и вот и все. Еще раз спасибо за отвечает.
Что вы пытаетесь сделать, и почему он не может ждать 15-30 секунд, прежде чем тайм-аут?
У меня была такая же проблема при подключении к сокету ,и я придумал следующее решение, оно отлично работает для меня. -
private bool CheckConnectivityForProxyHost(string hostName, int port) { if (string.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<Socket, IPEndPoint> 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) { } }
Я работал с Unity и имел некоторые проблемы с BeginConnect и другими асинхронными методами из сокета.
есть что-то, чем я не понимаю, но примеры кода, пока не работает для меня.
поэтому я написал этот кусок кода, чтобы заставить его работать. Я тестирую его в сети adhoc с android и ПК, а также в локальном на моем компьютере. Надеюсь, это поможет.
using System.Net.Sockets; using System.Threading; using System.Net; using System; using System.Diagnostics; class ConnexionParameter : Guardian { public TcpClient client; public string address; public int port; public Thread principale; public Thread thisthread = null; public int timeout; private EventWaitHandle wh = new AutoResetEvent(false); public ConnexionParameter(TcpClient client, string 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 trick. 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, string 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; } }и там очень простой сторожевой пес на C#, чтобы заставить его работать:
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); } }
Это похоже на ответ FlappySock, но я добавил к нему обратный вызов, потому что мне не понравился макет и как возвращалось логическое значение. В комментариях к этому ответу от Ника Миллера:
По моему опыту, если конечная точка может быть достигнута, но на конечной точке нет сервера, способного получить соединение, то AsyncWaitHandle.WaitOne будет сигнализирован, но сокет останется несоединеннымТак что мне кажется, полагаясь на то, что возвращается может быть опасно - я предпочитаю использовать
socket.Connected. Я устанавливаю нулевое логическое значение и обновляю его в функции обратного вызова. Я также обнаружил, что он не всегда заканчивает отчет о результате, прежде чем вернуться к основной функции - я тоже обрабатываю это и заставляю его ждать результата, используя тайм-аут:private static bool? areWeConnected = null; private static bool checkSocket(string 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"].ToString()); 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 } }по теме:Как проверить, если я связан?
Comments