Socket網絡通信(異步)——TCP


1、客戶端

public class AsyncTCP
    {
        #region 字段

        private Socket socket;
        private EndPoint localEP;
        private EndPoint remoteEP;
        private byte[] buffer = new byte[1024];//用於存放接收消息

        public event Action<byte[]> OnDataReceive;

        #endregion

        /// <summary>
        /// 建立TCP連接
        /// </summary> 
        public AsyncTCP(IPAddress localIP, int localPort, IPAddress remoteIP, int remotePort)
        {
            //創建一個Socket實例
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //綁定本地終結點
            localEP = new IPEndPoint(localIP, localPort);
            socket.Bind(localEP);
            //建立連接 
            remoteEP = new IPEndPoint(remoteIP, remotePort);
            socket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallBack), this.socket);
        } 

        /// <summary>
        /// 連接請求的回調
        /// </summary>
        /// <param name="ar"></param>
        private void ConnectCallBack(IAsyncResult ar)
        {
            Socket socketHandle = (Socket)ar.AsyncState;
            if (socketHandle.Connected)
            {
                socketHandle.EndConnect(ar);//結束掛起的異步連接請求
                socketHandle.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
            }
            else
            {
                MessageBox.Show("連接失敗");
            }
        }
        /// <summary>
        /// 接收數據的回調
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallBack(IAsyncResult ar)
        {
            if (socket == null) return;
            int length = socket.EndReceive(ar);//結束掛起的異步讀取
            if (length > 0)
            {
                byte[] data = new byte[length];
                Array.Copy(buffer, 0, data, 0, length);
                OnDataReceive(data);

                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
            } 
        }
        /// <summary>
        /// 發送數據
        /// </summary>
        /// <param name="data"></param>
        public void SendData(byte[] data)
        {
            if (socket != null)
            {
                socket.Send(data);
            }
        }

        /// <summary>
        /// 關閉
        /// </summary>
        public void Close()
        {
            if (socket != null)
            {
                socket.Close();
            }
        }

    }

 

2、服務端

public class AsyncSocketTCPServer : IDisposable
    {
        #region Fields
        /// <summary>
        /// 服務器程序允許的最大客戶端連接數
        /// </summary>
        private int _maxClient;

        /// <summary>
        /// 當前的連接的客戶端數
        /// </summary>
        private int _clientCount;

        /// <summary>
        /// 服務器使用的異步socket
        /// </summary>
        private Socket _serverSock;

        /// <summary>
        /// 客戶端會話列表
        /// </summary>
        private List<AsyncSocketState> _clients;

        private bool disposed = false;

        #endregion

        #region Properties

        /// <summary>
        /// 服務器是否正在運行
        /// </summary>
        public bool IsRunning { get; private set; }

        /// <summary>
        /// 監聽的IP地址
        /// </summary>
        public IPAddress Address { get; private set; }

        /// <summary>
        /// 監聽的端口
        /// </summary>
        public int Port { get; private set; }

        /// <summary>
        /// 通信使用的編碼
        /// </summary>
        public Encoding Encoding { get; set; }

        #endregion

        #region 構造函數

        /// <summary>
        /// 異步Socket TCP服務器
        /// </summary>
        /// <param name="listenPort">監聽的端口</param>
        public AsyncSocketTCPServer(int listenPort)
            : this(IPAddress.Any, listenPort, 1024)
        {
        }

        /// <summary>
        /// 異步Socket TCP服務器
        /// </summary>
        /// <param name="localEP">監聽的終結點</param>
        public AsyncSocketTCPServer(IPEndPoint localEP)
            : this(localEP.Address, localEP.Port, 1024)
        {
        }

        /// <summary>
        /// 異步Socket TCP服務器
        /// </summary>
        /// <param name="localIPAddress">監聽的IP地址</param>
        /// <param name="listenPort">監聽的端口</param>
        /// <param name="maxClient">最大客戶端數量</param>
        public AsyncSocketTCPServer(IPAddress localIPAddress, int listenPort, int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;

            _maxClient = maxClient;
            _clients = new List<AsyncSocketState>();
            _serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        }

        #endregion

        #region Method

        /// <summary>
        /// 啟動服務器
        /// </summary>
        public void Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(1024);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
        }

        /// <summary>
        /// 啟動服務器
        /// </summary>
        /// <param name="backlog">
        /// 服務器所允許的掛起連接序列的最大長度
        /// </param>
        public void Start(int backlog)
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(backlog);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
        }

        /// <summary>
        /// 停止服務器
        /// </summary>
        public void Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _serverSock.Close();
                //TODO 關閉對所有客戶端的連接             
            }
        }



        /// <summary>
        /// 處理客戶端連接
        /// </summary>
        /// <param name="ar"></param>
        private void HandleAcceptConnected(IAsyncResult ar)
        {
            if (IsRunning)
            {
                Socket server = (Socket)ar.AsyncState;
                Socket client = server.EndAccept(ar);
                //檢查是否達到最大的允許的客戶端數目         
                if (_clientCount >= _maxClient)
                {
                    //C-TODO 觸發事件         
                    RaiseOtherException(null);
                }
                else
                {
                    AsyncSocketState state = new AsyncSocketState(client);
                    lock (_clients)
                    {
                        _clients.Add(state);
                        _clientCount++;
                        RaiseClientConnected(state); //觸發客戶端連接事件         
                    }
                    state.RecvDataBuffer = new byte[client.ReceiveBufferSize];
                    //開始接受來自該客戶端的數據             
                    client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
                        new AsyncCallback(HandleDataReceived), state);
                }
                //接受下一個請求    
                server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState);
            }
        }

        /// <summary>
        /// 處理客戶端數據
        /// </summary>
        /// <param name="ar"></param>
        private void HandleDataReceived(IAsyncResult ar)
        {
            if (IsRunning)
            {
                AsyncSocketState state = (AsyncSocketState)ar.AsyncState;
                Socket client = state.ClientSocket;
                try
                {
                    //如果兩次開始了異步的接收,所以當客戶端退出的時候           
                    //會兩次執行EndReceive         
                    int recv = client.EndReceive(ar);
                    if (recv == 0)
                    {
                        //C- TODO 觸發事件 (關閉客戶端)         
                        Close(state);
                        RaiseNetError(state);
                        return;
                    }
                    //TODO 處理已經讀取的數據 ps:數據在state的RecvDataBuffer中          
                    //C- TODO 觸發數據接收事件          
                    RaiseDataReceived(state);
                }
                catch (SocketException)
                {
                    //C- TODO 異常處理         
                    RaiseNetError(state);
                }
                finally
                {
                    //繼續接收來自來客戶端的數據       
                    client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
                        new AsyncCallback(HandleDataReceived), state);
                }
            }
        }

        /// <summary>
        /// 發送數據
        /// </summary>
        /// <param name="state">接收數據的客戶端會話</param>
        /// <param name="data">數據報文</param>
        public void Send(AsyncSocketState state, byte[] data)
        {
            RaisePrepareSend(state);
            Send(state.ClientSocket, data);
        }

        /// <summary>
        /// 異步發送數據至指定的客戶端
        /// </summary>
        /// <param name="client">客戶端</param>
        /// <param name="data">報文</param>
        public void Send(Socket client, byte[] data)
        {
            if (!IsRunning)
                throw new InvalidProgramException("This TCP Scoket server has not been started.");
            if (client == null)
                throw new ArgumentNullException("client");
            if (data == null)
                throw new ArgumentNullException("data");
            client.BeginSend(data, 0, data.Length, SocketFlags.None,
                new AsyncCallback(SendDataEnd), client);

        }

        /// <summary>
        /// 發送數據完成處理函數
        /// </summary>
        /// <param name="ar">目標客戶端Socket</param>
        private void SendDataEnd(IAsyncResult ar)
        {
            ((Socket)ar.AsyncState).EndSend(ar);
            RaiseCompletedSend(null);
        }

        #endregion

        #region 事件

        /// <summary>
        /// 與客戶端的連接已建立事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> ClientConnected;
        /// <summary>
        /// 與客戶端的連接已斷開事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> ClientDisconnected;


        /// <summary>
        /// 觸發客戶端連接事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseClientConnected(AsyncSocketState state)
        {
            if (ClientConnected != null)
            {
                ClientConnected(this, new AsyncSocketEventArgs(state));
            }
        }


        /// <summary>
        /// 觸發客戶端連接斷開事件
        /// </summary>
        /// <param name="client"></param>
        private void RaiseClientDisconnected(Socket client)
        {
            if (ClientDisconnected != null)
            {
                ClientDisconnected(this, new AsyncSocketEventArgs("連接斷開"));
            }
        }

        /// <summary>
        /// 接收到數據事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> DataReceived;

        private void RaiseDataReceived(AsyncSocketState state)
        {
            if (DataReceived != null)
            {
                DataReceived(this, new AsyncSocketEventArgs(state));
            }
        }

        /// <summary>
        /// 發送數據前的事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> PrepareSend;

        /// <summary>
        /// 觸發發送數據前的事件
        /// </summary>
        /// <param name="state"></param>
        private void RaisePrepareSend(AsyncSocketState state)
        {
            if (PrepareSend != null)
            {
                PrepareSend(this, new AsyncSocketEventArgs(state));
            }
        }

        /// <summary>
        /// 數據發送完畢事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> CompletedSend;

        /// <summary>
        /// 觸發數據發送完畢的事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseCompletedSend(AsyncSocketState state)
        {
            if (CompletedSend != null)
            {
                CompletedSend(this, new AsyncSocketEventArgs(state));
            }
        }

        /// <summary>
        /// 網絡錯誤事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> NetError;

        /// <summary>
        /// 觸發網絡錯誤事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseNetError(AsyncSocketState state)
        {
            if (NetError != null)
            {
                NetError(this, new AsyncSocketEventArgs(state));
            }
        }

        /// <summary>
        /// 異常事件
        /// </summary>
        public event EventHandler<AsyncSocketEventArgs> OtherException;

        /// <summary>
        /// 觸發異常事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseOtherException(AsyncSocketState state, string descrip)
        {
            if (OtherException != null)
            {
                OtherException(this, new AsyncSocketEventArgs(descrip, state));
            }
        }

        private void RaiseOtherException(AsyncSocketState state)
        {
            RaiseOtherException(state, "");
        }
        #endregion


        #region Close
        /// <summary>
        /// 關閉一個與客戶端之間的會話
        /// </summary>
        /// <param name="state">需要關閉的客戶端會話對象</param>
        public void Close(AsyncSocketState state)
        {
            if (state != null)
            {
                state.Datagram = null;
                state.RecvDataBuffer = null;
                _clients.Remove(state);
                _clientCount--;
                //TODO 觸發關閉事件        
                state.Close();
            }
        }

        /// <summary>
        /// 關閉所有的客戶端會話,與所有的客戶端連接會斷開
        /// </summary>
        public void CloseAllClient()
        {
            foreach (AsyncSocketState client in _clients)
            {
                Close(client);
            }
            _clientCount = 0;
            _clients.Clear();
        }
        #endregion

        #region 釋放
        /// <summary>  
        /// Performs application-defined tasks associated with freeing,    
        /// releasing, or resetting unmanaged resources.   
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }


        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release 
        /// both managed and unmanaged resources; <c>false</c>
        /// to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                        if (_serverSock != null)
                        {
                            _serverSock = null;
                        }
                    }
                    catch (SocketException)
                    {
                        //TODO          
                        RaiseOtherException(null);
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }


    /// <summary>
    /// 異步Socket TCP事件參數類
    /// </summary>
    public class AsyncSocketEventArgs : EventArgs
    {
        /// <summary>
        /// 提示信息
        /// </summary>
        public string _msg;

        /// <summary>
        /// 客戶端狀態封裝類
        /// </summary>
        public AsyncSocketState _state;

        /// <summary>
        /// 是否已經處理過了
        /// </summary>
        public bool IsHandled { get; set; }

        public AsyncSocketEventArgs(string msg)
        {
            this._msg = msg;
            IsHandled = false;
        }

        public AsyncSocketEventArgs(AsyncSocketState state)
        {
            this._state = state;
            IsHandled = false;
        }

        public AsyncSocketEventArgs(string msg, AsyncSocketState state)
        {
            this._msg = msg;
            this._state = state;
            IsHandled = false;
        }

    }


    /// <summary>
    /// 異步SOCKET TCP 中用來存儲客戶端狀態信息的類
    /// </summary>
    public class AsyncSocketState
    {
        #region 字段
        /// <summary>
        /// 接收數據緩沖區
        /// </summary>
        private byte[] _recvBuffer;

        /// <summary>
        /// 客戶端發送到服務器的報文
        /// 注意:在有些情況下報文可能只是報文的片斷而不完整
        /// </summary>
        private string _datagram;

        /// <summary>
        /// 客戶端的Socket
        /// </summary>
        private Socket _clientSock;

        #endregion

        #region 屬性

        /// <summary>
        /// 接收數據緩沖區 
        /// </summary>
        public byte[] RecvDataBuffer
        {
            get
            {
                return _recvBuffer;
            }
            set
            {
                _recvBuffer = value;
            }
        }

        /// <summary>
        /// 存取會話的報文
        /// </summary>
        public string Datagram
        {
            get
            {
                return _datagram;
            }
            set
            {
                _datagram = value;
            }
        }

        /// <summary>
        /// 獲得與客戶端會話關聯的Socket對象
        /// </summary>
        public Socket ClientSocket
        {
            get
            {
                return _clientSock; 
            }
        }

        #endregion

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="cliSock">會話使用的Socket連接</param>
        public AsyncSocketState(Socket cliSock)
        {
            _clientSock = cliSock;
        }

        /// <summary>
        /// 初始化數據緩沖區
        /// </summary>
        public void InitBuffer()
        {
            if (_recvBuffer == null && _clientSock != null)
            {
                _recvBuffer = new byte[_clientSock.ReceiveBufferSize];
            }
        }

         /// <summary>
        /// 關閉會話
        /// </summary>
        public void Close()
        {
            //關閉數據的接受和發送
            _clientSock.Shutdown(SocketShutdown.Both);

            //清理資源
            _clientSock.Close();
        } 
    } 
服務端

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM