如何控制C#Socket的连接超时时间

最近在Socket编程的时候发现只能设置Send和Recieve的Timeout时间,而Connect方法的Timeout是固定的,大概有20-40s,如果用同步方法界面会卡死很长时间

下面搜集了几种通过异步的方式解决此问题的方法:

1.使用BeginConnect方法

IAsyncResult connResult = mySocket.BeginConnect(yourAddress, yourPort, null, null);
//WaitHandle.WaitOne 方法阻止当前线程,直到当前的 WaitHandle 收到信号
connResult.AsyncWaitHandle.WaitOne(2000, true);  //等待2秒

if (!connResult.IsCompleted)
{
  mySocket.Close();
  //处理连接不成功的动作
}
else
{
  //处理连接成功的动作
}

这种方法很好的控制了连接超时时间而且代码非常简单,但是界面仍然会有2秒的卡死产生。如果想解决该问题,则需要创建一个额外的线程来执行WaitOne方法。

2.使用ConnectAsync方法

SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += new EventHandler<SocketAsyncEventArgs>(AsyncConnected);
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(yourAddress), yourPort);
mySocket.ConnectAsync(e);

这是一种事件触发的方式,将连接成功后的动作放在Completed事件的处理过程中,从而使界面不会卡死。同时也可以创建一个额外线程来监视连接时间,从而达到控制连接超时的目的。
3.

class TimeOutSocket
{
    private static bool IsConnectionSuccessful = false;
    private static Exception socketexception;
    private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);

    public static TcpClient Connect(IPEndPoint remoteEndPoint, int timeoutMSec)
    {
        TimeoutObject.Reset();
        socketexception = null; 

        string serverip = Convert.ToString(remoteEndPoint.Address);
        int serverport = remoteEndPoint.Port;          
        TcpClient tcpclient = new TcpClient();
       
        tcpclient.BeginConnect(serverip, serverport,
            new AsyncCallback(CallBackMethod), tcpclient);

        if (TimeoutObject.WaitOne(timeoutMSec, false))
        {
            if (IsConnectionSuccessful)
            {
                return tcpclient;
            }
            else
            {
                throw socketexception;
            }
        }
        else
        {
            tcpclient.Close();
            throw new TimeoutException("TimeOut Exception");
        }
    }
    private static void CallBackMethod(IAsyncResult asyncresult)
    {
        try
        {
            IsConnectionSuccessful = false;
            TcpClient tcpclient = asyncresult.AsyncState as TcpClient;
            
            if (tcpclient.Client != null)
            {
                tcpclient.EndConnect(asyncresult);
                IsConnectionSuccessful = true;
            }
        }
        catch (Exception ex)
        {
            IsConnectionSuccessful = false;
            socketexception = ex;
        }
        finally
        {
            TimeoutObject.Set();
        }
    }
}

这里,ManualResetEvent的WaitOne(TimeSpan, Boolean)起到了主要的作用。它将阻止当前线程,直到ManualResetEvent对象被Set或者超过timeout时间。上面的代码中,调用BeginConnect后通过WaitOne方法阻止当前线程,如果在timeoutMSec时间内连接成功,将在CallBackMethod回调中调用TimeoutObject.Set,解除被阻塞的连接线程并返回;否则,连接线程会在等待超时后,主动关闭连接并抛出TimeoutException。
4.

 private string ConnectSocket(IPEndPoint ipep, Socket s)
        {
            string m = "";
            try
            {
                s.Connect(ipep);
            }
            catch (System.Exception ex)
            {
                m = ex.Message;
            }
            return m;
        }

        /// <summary>
        /// 创建TCP连接
        /// </summary>
        /// <returns>连接状态</returns>
        public bool Modbus_TCP_Open()
        {
            int Timeout = 500;
            //创建一个套接字   
            //将服务器IP地址存放在字符串
            //将端口号强制为32位整型,存放在port中
            IPEndPoint ie = new IPEndPoint(IPAddress.Parse(IP_Address), Convert.ToInt32(PC_Port));
            newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            CSD d = ConnectSocket;
            IAsyncResult iaresult = d.BeginInvoke(ie, newclient, null, null);
            bool connectSuccess = iaresult.AsyncWaitHandle.WaitOne(Timeout, false);
            
            if (!connectSuccess)
            {
                MessageBox.Show(string.Format("失败!错误信息:{0}", "连接超时"));
                return false;
            }
            //EndInvoke方法一直阻塞,直到被调用的方法执行完毕。会导致用户界面假死
            string m = d.EndInvoke(iaresult);
            if (!string.IsNullOrEmpty(m))
            {
                MessageBox.Show(string.Format("失败!错误信息:{0}", m));
                return false;
            }
            return true;
        }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值