C#網絡編程系列文章(一)之Socket實現異步TCPserver

本文做者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 轉載請註明出處編程

Socket異步TCPserver 相信搞過網絡編程的人來講這個TCP一點也不陌生吧,在C#中微軟已經幫咱們封裝過了一個TcpListener和TcpClient這兩個類了。實現了對於套接字的封裝,但是呢實際上仍是不怎麼好用。因此咱們用Socket來實現一個異步的TCPserver。服務器

在本文中我僅僅給出server端代碼。client代碼本身可以找找別處,畢竟我僅僅是爲了寫出一個好的server端網絡

如下是代碼app

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Net;異步

namespace NetFrame.Net.TCP.Sock.Asynchronous { /// <summary> /// Socket實現的異步TCP服務器 /// </summary> public class AsyncSocketTCPServer : IDisposable { #region Fields /// <summary> /// 服務器程序贊成的最大客戶端鏈接數 /// </summary> private int _maxClient;socket

/// <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>
    /// 監聽的port
    /// </summary>
    public int Port { get; private set; }
    /// <summary>
    /// 通訊使用的編碼
    /// </summary>
    public Encoding Encoding { get; set; }


    #endregion

    #region 構造函數

    /// <summary>
    /// 異步Socket TCP服務器
    /// </summary>
    /// <param name="listenPort">監聽的port</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">監聽的port</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
}

}函數

事件參數類 using System; using System.Collections.Generic; using System.Linq; using System.Text;this

namespace NetFrame.Net.TCP.Sock.Asynchronous { /// <summary> /// 異步Socket TCP事件參數類 /// </summary> public class AsyncSocketEventArgs:EventArgs { /// <summary> /// 提示信息 /// </summary> public string _msg;編碼

/// <summary>
    /// client狀態封裝類
    /// </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;
    }
}

}spa

用戶狀態封裝 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets;

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

/// <summary>
    /// 客戶端發送到server的報文
    /// 注意:在有些狀況下報文可能僅僅是報文的片段而不完整
    /// </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();
    }
}

}

相關文章
相關標籤/搜索