c# 创建socket连接辅助类-可指定超时时间

using AD.SocketForm.Model;
using NLog;
using System;
using System.Net.Sockets;
using System.Threading;

namespace AD.SocketForm.Service
{
    /// <summary>
    /// Socket连接类-可指定超时时间
    /// 参考网址://www.cnblogs.com/weidagang2046/archive/2009/02/07/1385977.html
    /// </summary>
    public class SocketNewService
    {
        private Logger _logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 连接socket
        /// </summary>
        /// <param name="model"></param>
        /// <param name="timeout">单位:毫秒</param>
        /// <returns></returns>
        public Socket Create(HubModel model, int timeout)
        {
            var isConnected = false;
            var manualResetEvent = new ManualResetEvent(false);
            var tcpClient = new TcpClient();

            #region 异步方法委托
            Action<IAsyncResult> action = (asyncresult) =>
            {
                try
                {
                    TcpClient tcpclient = asyncresult.AsyncState as TcpClient;

                    if (tcpclient.Client != null)
                    {
                        tcpclient.EndConnect(asyncresult);
                        isConnected = true;
                    }
                    //Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    _logger.Error(string.Format("获取socket异常,message:{0},stacktrace:{1}", ex.Message, ex.StackTrace));
                    isConnected = false;
                }
                finally
                {
                    manualResetEvent.Set();
                }
            };
            #endregion

            tcpClient.BeginConnect(model.IP, model.Port, new AsyncCallback(action), tcpClient);

            //判断在指定的时间以内是否收到释放锁的通知
            if (manualResetEvent.WaitOne(timeout, false))
            {
                //Console.WriteLine("连接成功");
                if (isConnected)
                {
                    return tcpClient.Client;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                //Console.WriteLine("超时");
                tcpClient.Close();
                return null;
            }
        }

        /// <summary>
        /// 关闭socket
        /// </summary>
        /// <param name="socket"></param>
        public void Close(Socket socket)
        {
            if (socket != null)
            {
                socket.Close();
                socket = null;
            }
        }

        /// <summary>
        /// 判断Socket是否已连接
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public bool IsConnected(Socket socket)
        {
            if (socket == null || socket.Connected == false)
            {
                return false;
            }

            bool blockingState = socket.Blocking;
            try
            {
                byte[] tmp = new byte[1];
                socket.Blocking = false;
                socket.Send(tmp, 0, 0);
                return true;
            }
            catch (SocketException e)
            {
                // 产生 10035 == WSAEWOULDBLOCK 错误,说明被阻止了,但是还是连接的
                if (e.NativeErrorCode.Equals(10035))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.Error(string.Format("检查Socket是否可连接时异常,message:{0},stacktrace:{1}", ex.Message, ex.StackTrace));
                return false;
            }
            finally
            {
                socket.Blocking = blockingState;    // 恢复状态
            }
        }
    }
}

主要是通过两点:

1、通过if (manualResetEvent.WaitOne(timeout, false))来处理。它的作用是:阻止当前线程N毫秒,期间如果有调用manualResetEvent.Set()立即取消当前线程的阻塞,并且返回true;如果没有调用,时间到了后依然取消当前线程的阻塞,但是返回false。

2、通过tcpClient.BeginConnect(model.IP, model.Port, new AsyncCallback(action), tcpClient)建立tcp连接。这句话的意思是以异步的方式建立tcp连接,成功之后调用指定的回调方法。即new AsyncCallback(action)

另外,这个类把回调方法写在了Create方法里面,原因是方便处理isConnected的状态,无需考虑线程同步。因为这个辅助类实例化后,是被驻留在内存里面的,有可能会被多次使用。为了线程安全,所以写在了里面。

posted @ 2019-11-08 19:51  屌丝大叔的笔记  阅读(689)  评论(0编辑  收藏  举报