C# 异步Socket客户端通讯

最近在项目中由于同步阻塞通讯带来程序效率过低学习了异步Socket通讯。这里粘贴Socket客户端异步非阻塞工具类代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace com.qjcz.weighing.Utils
{
    public class AsyncTCPClient
    {
        /// <summary>
        /// 内部类,用于消息接收
        /// </summary>
        internal class SocketObject
        {
            public string KeyID = "";
            public Socket WorkSocket = null;
            public const int BufferSize = 1024;
            public byte[] Buffer = new byte[BufferSize];
            public StringBuilder sbBuffer = new StringBuilder();
        }
        #region 变量

        private Socket mSocket = null;
        private string localIPAddress = "";
        private int localPort = 0;
        private string remoteIPAddress = "";
        private int remotePort = 0;
        private string keyID = "";
        private bool IsExit = false;
        private SocketObject so = new SocketObject();

        #endregion

        #region 变量属性

        /// <summary>
        /// Socket标志
        /// </summary>
        public string KeyID
        {
            get
            {
                return keyID;
            }
        }

        /// <summary>
        /// 本机地址
        /// </summary>
        public string LocalIPAddress
        {
            get
            {
                return localIPAddress;
            }
        }

        /// <summary>
        /// 本机端口
        /// </summary>
        public int LocalPort
        {
            get
            {
                return localPort;
            }
        }

        /// <summary>
        /// 主机地址
        /// </summary>
        public string RemoteIPAddress
        {
            get
            {
                return remoteIPAddress;
            }
        }

        /// <summary>
        /// 主机端口
        /// </summary>
        public int RemotePort
        {
            get
            {
                return remotePort;
            }
        }

        /// <summary>
        /// 消息的终止判断符
        /// </summary>
        public static string EndChar
        {
            get
            {
                return new string((char)0, 1);
            }
        }

        #endregion

        #region 代理委托

        /// <summary>
        /// Socket异常错误事件
        /// </summary>
        /// <param name="aKeyID">异常错误所有者的标志值</param>
        /// <param name="aErrorMessage">异常错误信息</param>
        public delegate void SocketErrorHandler(string aKeyID, string aErrorMessage);

        /// <summary>
        /// 接收二进制数据
        /// </summary>
        /// <param name="aData">接收到的数据</param>
        public delegate void BinaryDataAvailableHandler(byte[] aData);

        /// <summary>
        /// 接收字符串数据
        /// </summary>
        /// <param name="aData">接收到的数据</param>
        public delegate void StringDataAvailableHandler(string aData);

        #endregion

        #region 事件声明

        public event SocketErrorHandler OnSocketError;
        public event BinaryDataAvailableHandler OnBinaryDataAvailable;
        public event StringDataAvailableHandler OnStringDataAvailable;

        #endregion

        #region 事件代理方法

        /// <summary>
        /// 显示异常错误信息
        /// </summary>
        /// <param name="aKeyID">异常错误所有者的标志值</param>
        /// <param name="aErrorMessage">异常错误信息</param>
        private void DisplayError(string aKeyID, string aErrorMessage)
        {
            if (OnSocketError != null)
            {
                OnSocketError(aKeyID, aErrorMessage);
            }
        }

        /// <summary>
        /// 接收二进制数据
        /// </summary>
        /// <param name="aData">接收到的数据</param>
        private void BinaryDataAvailable(byte[] aData)
        {
            if (OnBinaryDataAvailable != null)
            {
                OnBinaryDataAvailable(aData);
            }
        }

        /// <summary>
        /// 接收字符串数据
        /// </summary>
        /// <param name="aData">接收到的数据</param>
        private void StringDataAvailable(string aData)
        {
            if (OnStringDataAvailable != null)
            {
                OnStringDataAvailable(aData);
            }
        }

        #endregion

        #region 内部方法

        /// <summary>
        /// 异步接收数据
        /// </summary>
        /// <param name="ar">IAsyncResult接口对象</param>
        private void AsyncDataReceive(IAsyncResult ar)
        {
            SocketObject so = (SocketObject)ar.AsyncState;
            try
            {
                if (IsExit == false)
                {
                    //接收的数据长度
                    int iReceiveCount = so.WorkSocket.EndReceive(ar);
                    if (iReceiveCount > 0)
                    {
                        //so.sbBuffer.Append(Encoding.Default.GetString(so.Buffer, 0, iReceiveCount));
                        //string strReceive = so.sbBuffer.ToString();
                        //if (strReceive.Substring(strReceive.Length - 1, 1) == EndChar)
                        //{
                            //本次接收
                           // strReceive = strReceive.Remove(strReceive.Length - 1, 1);

                            //通过接收事件调用外部用户接口方法
                            BinaryDataAvailable(so.Buffer);
                            
                           //StringDataAvailable(strReceive);
                            //清空数据
                            so.sbBuffer.Remove(0, so.sbBuffer.Length);
                       // }
                        if (IsExit == false)
                        {
                            //递归实现连续接收
                            so.WorkSocket.BeginReceive(so.Buffer, 0, so.Buffer.Length, SocketFlags.None, new AsyncCallback(AsyncDataReceive), so);
                        }
                    }
                    else
                    {
                        Disconnect();
                    }
                }
                else
                {
                    Disconnect();
                }
            }
            catch (Exception ex)
            {
                DisplayError(KeyID, ex.Message);
            }
        }

        /// <summary>
        /// 异步发送消息
        /// </summary>
        /// <param name="ar">IAsyncResult接口对象</param>
        private void AsyncSend(IAsyncResult ar)
        {
            try
            {
                int iSendCount = mSocket.EndSend(ar);
            }
            catch (Exception ex)
            {
                DisplayError(KeyID, ex.Message);
            }
        }

        /// <summary>
        /// 发送消息(异步发送)
        /// </summary>
        /// <param name="aData">要发送的消息</param>
        private void Send(byte[] aData)
        {
            try
            {
                mSocket.BeginSend(aData, 0, aData.Length, SocketFlags.None, new AsyncCallback(AsyncSend), null);
            }
            catch (Exception ex)
            {
                DisplayError(KeyID, ex.Message);
            }
        }
        /// <summary>
        /// 异步连接完成回调函数
        /// </summary>
        /// <param name="ar"></param>
        public void AsyncConnect(IAsyncResult ar)
        {
            Socket sock = (Socket)ar.AsyncState;
            try
            {
                sock.EndConnect(ar);
                if (sock.Connected)
                {
                    //启动消息接收事件
                    so.KeyID = KeyID;
                    so.WorkSocket = sock;
                    if (IsExit == false)
                    {
                        so.WorkSocket.BeginReceive(so.Buffer, 0, so.Buffer.Length, SocketFlags.None, new AsyncCallback(AsyncDataReceive), so);
                    }
                }
                else
                {
                    new Exception("Unable to connect to remote machine, Connect Failed!");
                }
            }
            catch (Exception ex)
            {
                DisplayError(KeyID, ex.Message);
            }
        }

        #endregion

        #region 对外开发的接口方法

        /// <summary>
        /// 初始化本机Socket通信机制
        /// </summary>
        /// <param name="aLocalIPAddress">本机地址</param>
        /// <param name="aLocalPort">本机端口</param>
        /// <returns>返回操作是否成功</returns>
        public bool InitSocket(string aLocalIPAddress, int aLocalPort)
        {
            bool bActive = false;
            mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            LingerOption lo = new LingerOption(false, 10);
            mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
            try
            {
                IPAddress ip = Dns.GetHostAddresses(aLocalIPAddress)[0];
                if (aLocalPort == 0)
                {
                    Random rd = new Random(5000);
                    aLocalPort = rd.Next(30000);
                }
                localIPAddress = ip.ToString();
                localPort = aLocalPort;
                IPEndPoint ipe = new IPEndPoint(ip, aLocalPort);
                keyID = Guid.NewGuid().ToString();
                mSocket.Bind(ipe);
                bActive = true;
            }
            catch (Exception ex)
            {
                bActive = false;
                DisplayError(KeyID, ex.Message);
            }
            return bActive;
        }

        /// <summary>
        /// 连接主机
        /// </summary>
        /// <param name="aRemoteIPAddress">主机地址</param>
        /// <param name="aRemotePort">主机端口</param>
        /// <returns>返回操作是否成功</returns>
        public bool Connect(string aRemoteIPAddress, int aRemotePort)
        {
            if (mSocket == null)
                return false;
            try
            {
                remoteIPAddress = aRemoteIPAddress;
                remotePort = aRemotePort;
                mSocket.Blocking = false;
                mSocket.BeginConnect(remoteIPAddress, remotePort, new AsyncCallback(AsyncConnect), mSocket);
            }
            catch (Exception ex)
            {
                DisplayError(KeyID, ex.Message);
            }
            return mSocket.Connected;
        }

        /// <summary>
        /// 断开与主机的连接
        /// </summary>
        /// <returns></returns>
        public bool Disconnect()
        {
            try
            {
                if (mSocket != null)
                {
                    if (mSocket.Connected)
                    {
                        mSocket.Shutdown(SocketShutdown.Both);
                        mSocket.Close();
                        mSocket = null;
                    }
                    else
                    {
                        mSocket = null;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                DisplayError(keyID, ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 发送消息(异步发送)
        /// </summary>
        /// <param name="aMessage">要发送的消息</param>
        public void Send(string aMessage)
        {
            string strMessage = aMessage;
            //判断要发送的消息是不是以消息终止判断符号结尾,如果没有则自动加上
            if (strMessage.Substring(strMessage.Length - 1, 1) != EndChar)
            {
                strMessage = strMessage + EndChar;
            }
            Send(Encoding.Default.GetBytes(strMessage));
        }

        /// <summary>
        /// 发送消息(异步发送)
        /// </summary>
        /// <param name="aMessage">要发送的消息</param>
        public void Send(byte[] aMessage, int aMessageLength)
        {
            StringBuilder SendBuffer = new StringBuilder();
            SendBuffer.Append(Encoding.UTF8.GetString(aMessage, 0, aMessageLength));
            string strSend = SendBuffer.ToString();
            Send(strSend);
        }

        #endregion
    }
}

猜你喜欢

转载自blog.csdn.net/zwgoldroad/article/details/82770831