如何配置套接字连接超时

nin*_*kin 98 c# sockets timeout

当客户端尝试连接到断开连接的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);
}
Run Code Online (Sandbox Code Playgroud)

Fla*_*cks 140

我找到了这个.比接受的答案更简单,并与.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.");
}

//... 
Run Code Online (Sandbox Code Playgroud)

  • 好吧,对这一点的投入很少 - 我喜欢这个并且它的代码少得多......但是!成功不是正确的条件.相反,添加if(!_socket.Connected)并且它工作得更好.我会给它+1一个更少的方面. (20认同)
  • 如果我想增加超时而不是减少它会怎么样?我认为异步方法只是让你让代码不等待20秒(套接字连接中设置的内部超时).但是如果连接需要更长时间,则BeginConnect仍会停止.或者,BeginConnect内部是否会永远等待?我有一个非常慢的连接,有时连接需要30-40秒,而第21秒的超时很常发生. (9认同)
  • 另一件事情也是注意......如果没有将`null`放入`callback`而你计划`EndConnect()`,如果套接字已经'关闭'那么这将给你一个例外.所以一定要检查...... (3认同)
  • @TravisWhidden可以确认,这非常重要!根据我的经验,如果可以到达终点,但端点上没有能够接收连接的服务器,那么将发出"AsyncWaitHandle.WaitOne"信号,但套接字将保持未连接状态. (3认同)
  • 取决于你的两个终点.如果他们都在数据中心,那么1秒应该是充足的,3个是好的,10个是好的.如果一端在移动设备上,例如智能手机,那么您可能需要30秒. (2认同)

bev*_*qua 29

我的看法:

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.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


pic*_*rap 22

我刚写了一个扩展类,以便在连接中允许超时.使用它与使用标准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)
            { }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • GhostDoc的粉丝,是吗?;-)"Asyncs the connect" - 经典的GhostDoc WTFness. (8认同)
  • :) 是的,有时甚至没有读者阅读所生成的内容。 (2认同)
  • `socket.EndConnect`需要大约10秒才能关闭,所以函数不会在时间跨度之后但在timepan + endConnect之后返回 (2认同)

Ole*_*nko 9

可能为时已晚,但有基于 Task.WaitAny (c# 5 +) 的简洁解决方案:

 public static bool ConnectWithTimeout(this Socket socket, string host, int port, int timeout)
        {
            bool connected = false;
            Task result = socket.ConnectAsync(host, port);               
            int index = Task.WaitAny(new[] { result }, timeout);
            connected = socket.Connected;
            if (!connected) {
              socket.Close();
            }

            return connected;
        }
Run Code Online (Sandbox Code Playgroud)


Adi*_*gal 8

我不用C#编程,但是在C中,我们通过使套接字无阻塞然后将fd放在select/poll循环中来解决同样的问题,其中超时值等于我们愿意等待连接的时间量成功.

我在Visual C++中找到了这个,并且那里的解释也倾向于我之前解释过的select/poll机制.

根据我的经验,您无法更改每个插槽的连接超时值.您可以更改它(通过调整OS参数).


nin*_*kin 5

我通过使用 Socket.ConnectAsync 方法而不是 Socket.Connect 方法解决了这个问题。调用Socket.ConnectAsync(SocketAsyncEventArgs)后,启动一个定时器(timer_connection),如果时间到,检查socket连接是否连接(if(m_clientSocket.Connected)),如果没有,则弹出超时错误。

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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 当计时器停止时,您会显示一条错误消息,对吗?这如何阻止您的 TCP 堆栈实际连接。想象一个场景,远程主机在 2 秒以上,即 rto &gt; 2。您的计时器将停止,您将打印错误消息。但是,TCP 不受您的计时器控制。它仍然会尝试连接,并且可能会在 2 秒后成功连接。C# 是否提供了取消“连接”请求或关闭套接字的功能。您的计时器解决方案等于在 2 秒后检查连接是否成功。 (2认同)