西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁編程開發(fā)C#.NET → C#封裝server與client實現(xiàn)異步套接字解決方案

C#封裝server與client實現(xiàn)異步套接字解決方案

相關(guān)軟件相關(guān)文章發(fā)表評論 來源:BLoodMaster時間:2012/6/1 8:31:12字體大小:A-A+

作者:BLoodMaster點擊:93次評論:0次標(biāo)簽: 異步

  • 類型:行業(yè)軟件大。1.5M語言:中文 評分:5.0
  • 標(biāo)簽:
立即下載

   最近半年以來都在從事suse10下的C++開發(fā),開發(fā)工具也從豪門visual studio10降到了代碼查看工具source insight。不過不得不說source insight閱讀代碼的效率絕對超過visual studio,雖然visual studio也能設(shè)置哪些功能,但真心沒source insight順手。不過悲劇的就是寫代碼的支持比文本好不了多少,調(diào)試的話,只能上傳到suse10服務(wù)器上去然后慢慢的gdb調(diào)試了,最頭大的就是那個makefile的編寫,實在讓人累。還是懷念windows下那種豪華的日子。

     廢話不多說了,我寫這篇文章不是為了訴苦的,只是為了繼續(xù)寫網(wǎng)絡(luò)這邊的。以前寫過windows下的C++的網(wǎng)絡(luò)編程的一些日子,雖然也被噴過不少,不過今天我還是要來寫網(wǎng)絡(luò)編程,只是語言更換為豪華的C#。之所以說C#豪華,相信同時使用C#與C++的人能體會到。

     frame work實在是太強大了,基本我就關(guān)注一點點東西就行了,很多類似工具的東西都是可以直接拿過來使用,而且最為關(guān)鍵的是我們在天朝,不用花錢用企業(yè)版,小小鄙視下自己,不過我還是會繼續(xù)支持山寨盜版,誰讓我是屌絲呢。

      今天文章中寫的是異步,純粹的異步,當(dāng)然很多人看來很簡單了,而且里面很多東西值得商榷,不過說真的,我真心感謝C#的線程池,不然我還要自己去寫個threadpool。而且我沒辦法保證我寫的沒問題。

     直接上代碼了,不講思路了,沒時間,最近太忙,已經(jīng)幾天沒睡好了。

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

namespace PPT.Comm
{
    /// <summary>
    /// 接收數(shù)據(jù)流
    /// </summary>
    /// <param name="m_pSocket">異步套接字</param>
    /// <param name="m_pDatagram">接收到的數(shù)據(jù)流</param>
    public delegate void AsyncDataAcceptedEventHandler(AsyncSocket m_pSocket, byte[] m_pDatagram);

    /// <summary>
    /// 發(fā)送完畢
    /// </summary>
    /// <param name="m_pSocket">異步套接字</param>
    /// <param name="m_pIsSuccess">發(fā)送結(jié)果</param>
    public delegate void AsyncDataSendedEventHandler(AsyncSocket m_pSocket, bool m_pIsSuccess);

    /// <summary>
    /// 接收連接委托
    /// </summary>
    /// <param name="m_pSocket">異步套接字</param>
    public delegate void AsyncSocketAcceptEventHandler(AsyncSocket m_pSocket);

    /// <summary>
    /// 關(guān)閉連接委托
    /// </summary>
    /// <param name="m_pSocket">異步套接字</param>
    public delegate void AsyncSocketClosedEventHandler(AsyncSocket m_pSocket);

    /// <summary>
    /// State object for receiving data from remote device.
    /// </summary>
    class StateObject
    {
        // Client socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024 * 256;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
    }

    /// <summary>
    /// 異步SOCKET
    /// </summary>
    public class AsyncSocket
    {
        #region 私有字段 成員

        private Socket m_socket = null;                                             //socket
        string m_id = "";                                                           //socket唯一標(biāo)識,GUID

        private readonly bool m_isSerevr;                                           //服務(wù)器標(biāo)志位
        private int m_iBackBag;
        private string m_ipAddress;
        private int m_port;

        private AsyncDataAcceptedEventHandler m_onAsyncDataAcceptedEvent = null;    //接收數(shù)據(jù)流
        private AsyncDataSendedEventHandler m_onAsyncDataSendedEvent = null;        //發(fā)送結(jié)束
        private AsyncSocketAcceptEventHandler m_onAsyncSocketAcceptEvent = null;    //接收連接
        private AsyncSocketClosedEventHandler m_onAsyncSocketClosedEvent = null;    //關(guān)閉連接
 
        #endregion

        #region 公共屬性 成員

        /// <summary>
        /// 獲取SOCKET標(biāo)志位
        /// </summary>
        public string ID 
        {
            get 
            { 
                return m_id;
            } 
        }

        /// <summary>
        /// 設(shè)置或獲取機器標(biāo)志位
        /// </summary>
        public string MachineKey 
        { 
            set; 
            get; 
        }

        /// <summary>
        /// 獲取、設(shè)置連接對象
        /// </summary>
        public Socket LinkObject
        {
            get
            {
                return m_socket;
            }
            set
            {
                m_socket = value;
            }
        }

        /// <summary>
        /// 設(shè)置或獲取線程退出標(biāo)識
        /// </summary>
        public bool IsExit { set; get; }

        #endregion

        #region 公共事件 成員

        /// <summary>
        /// 連接關(guān)閉事件
        /// </summary>
        public event AsyncSocketClosedEventHandler AsyncSocketClosedEvent
        {
            add
            {
                m_onAsyncSocketClosedEvent += value;
            }
            remove
            {
                m_onAsyncSocketClosedEvent -= value;
            }
        }

        /// <summary>
        /// 連接接收事件
        /// </summary>
        public event AsyncSocketAcceptEventHandler AsyncSocketAcceptEvent
        {
            add
            {
                m_onAsyncSocketAcceptEvent += value;
            }
            remove
            {
                m_onAsyncSocketAcceptEvent -= value;
            }
        }

        /// <summary>
        /// 數(shù)據(jù)接收完成事件
        /// </summary>
        public event AsyncDataAcceptedEventHandler AsyncDataAcceptedEvent
        {
            add
            {
                this.m_onAsyncDataAcceptedEvent += value;
            }
            remove
            {
                this.m_onAsyncDataAcceptedEvent -= value;
            }
        }

        /// <summary>
        /// 數(shù)據(jù)發(fā)送完成事件
        /// </summary>
        public event AsyncDataSendedEventHandler AsyncDataSendedEvent
        {
            add
            {
                m_onAsyncDataSendedEvent += value;
            }
            remove
            {
                m_onAsyncDataSendedEvent -= value;
            }
        }

        #endregion

        #region 構(gòu)造函數(shù) 成員

        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="m_pHostAddrss">主機地址,可為機器名或者IP</param>
        /// <param name="m_pHostPort">主機端口</param>
        /// <param name="m_pIsAsServer">是否作為服務(wù)器,默認為false</param>
        /// <param name="m_pICount">支持多少個客戶端</param>
        public AsyncSocket(string m_pHostAddrss, int m_pHostPort, bool m_pIsAsServer = false, int m_pIBackBag = 10)
        {
            m_isSerevr = m_pIsAsServer;
            m_iBackBag = m_pIBackBag;
            m_ipAddress = m_pHostAddrss;
            m_port = m_pHostPort;
            m_id = Guid.NewGuid().ToString();
        }

        /// <summary>
        /// 構(gòu)造函數(shù),用于服務(wù)器構(gòu)造與客戶端的異步socket
        /// </summary>
        /// <param name="LinkObject">客戶端socket</param>
        private AsyncSocket(Socket linkObject)
        {
            m_socket = linkObject;
            m_id = Guid.NewGuid().ToString();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 打開通道
        /// </summary>
        public void AsyncOpen()
        {
            if (m_isSerevr)
            {
                IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[0];
                IPEndPoint ipe = new IPEndPoint(ip, m_port);
                m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_socket.Bind(ipe);
                m_socket.Listen(m_iBackBag);
                m_socket.BeginAccept(new AsyncCallback(AcceptCallBack), null);//異步
            }
            else
            {
                IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[0];
                IPEndPoint ipe = new IPEndPoint(ip, m_port);
                m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_socket.Connect(ipe);
            }
        }

        /// <summary>
        /// 發(fā)送二進制數(shù)據(jù)
        /// </summary>
        /// <param name="SendData"></param>
        public void AsyncSend(byte[] SendData)
        {
            m_socket.BeginSend(SendData, 0, SendData.Length, 0, new AsyncCallback(SendCallBack), m_socket);
        }

        /// <summary>
        /// 關(guān)閉通道
        /// </summary>
        public void AsyncClose()
        {
            if (!m_isSerevr)
            {
                m_socket.Shutdown(SocketShutdown.Both);//關(guān)閉接收發(fā)送流
                m_socket.BeginDisconnect(false, CloseCallBack, m_socket);//開始嘗試斷開
            }
            else 
            {
                m_socket.Shutdown(SocketShutdown.Both);//關(guān)閉接收發(fā)送流
                Thread.Sleep(200);//等待現(xiàn)有任務(wù)處理完成
                m_socket.Dispose();//釋放所有本地資源
            }
        }

        /// <summary>
        /// 開始接受數(shù)據(jù),連接建立之后,調(diào)用此方法
        /// </summary>
        public void BeginAcceptData()
        {
            //開始接收數(shù)據(jù)
            StateObject state = new StateObject();
            state.workSocket = m_socket;
            m_socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }

        #endregion

        #region 私有方法 成員

        #endregion

        #region 回調(diào)函數(shù) 成員

        /// <summary>
        /// 接受客戶端連接處理
        /// </summary>
        /// <param name="ar"></param>
        private void AcceptCallBack(IAsyncResult ar)
        {
            Socket handler = m_socket.EndAccept(ar);
            AsyncSocket NewSocket = new AsyncSocket(handler);

            //激發(fā)事件,異步觸發(fā)
            if (m_onAsyncSocketAcceptEvent != null)
                foreach (AsyncSocketAcceptEventHandler item in m_onAsyncSocketAcceptEvent.GetInvocationList())
                    item.BeginInvoke(NewSocket, null, null);

            //繼續(xù)投遞監(jiān)聽請求
            m_socket.BeginAccept(new AsyncCallback(AcceptCallBack), null);
        }

        /// <summary>
        /// 接受字節(jié)流處理
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                StateObject state = ar.AsyncState as StateObject;
                //讀取數(shù)據(jù)
                int bytesRead = m_socket.EndReceive(ar);
                if (bytesRead > 0)
                {
                    byte[] _Readbyte = new byte[bytesRead];
                    Array.Copy(state.buffer, 0, _Readbyte, 0, bytesRead);
                    //接收完成,激發(fā)事件
                    if (m_onAsyncDataAcceptedEvent != null)
                        foreach (AsyncDataAcceptedEventHandler item in m_onAsyncDataAcceptedEvent.GetInvocationList())
                            item.BeginInvoke(this, _Readbyte, null, null);

                    state = new StateObject();//繼續(xù)投遞接收委托
                    state.workSocket = m_socket;
                    m_socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                }
            }
            catch (SocketException)
            {
                if (m_onAsyncSocketClosedEvent != null)
                    foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
                        item.BeginInvoke(this, null, null);
            }
        }

        /// <summary>
        /// 發(fā)送結(jié)束處理
        /// </summary>
        /// <param name="ar"></param>
        private void SendCallBack(IAsyncResult ar)
        {
            try
            {
                m_socket.EndSend(ar);
                if (m_onAsyncDataSendedEvent != null)
                    foreach (AsyncDataSendedEventHandler item in m_onAsyncDataSendedEvent.GetInvocationList())
                        item.BeginInvoke(this, true, null, null);
            }
            catch (SocketException)
            {
                if (m_onAsyncDataSendedEvent != null)
                    foreach (AsyncDataSendedEventHandler item in m_onAsyncDataSendedEvent.GetInvocationList())
                        item.BeginInvoke(this, false, null, null);

                if (m_onAsyncSocketClosedEvent != null)
                    foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
                        item.BeginInvoke(this, null, null);
            }
        }

        /// <summary>
        /// 關(guān)閉后處理
        /// </summary>
        /// <param name="ar"></param>
        private void CloseCallBack(IAsyncResult ar)
        {
            try
            {
                m_socket.EndDisconnect(ar);
                m_socket.Dispose();
                if (m_onAsyncDataSendedEvent != null)
                    foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
                        item.BeginInvoke(this, null, null);
            }
            catch (SocketException)
            {
                if (m_onAsyncSocketClosedEvent != null)
                    foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
                        item.BeginInvoke(this, null, null);
            }  
        }

        #endregion
    }
}

   代碼注釋還是蠻詳細的,相信你看了也沒什么不懂的地方。唯一讓我不爽的是我異步事件不得不

                foreach (AsyncSocketAcceptEventHandler item in m_onAsyncSocketAcceptEvent.GetInvocationList())

                    item.BeginInvoke(NewSocket, null, null); 

這樣的寫法,很蛋疼。也試驗了

Action asyncAction = () => m_onAsyncSocketAcceptEvent ();

asyncAction.BeginInvoke( null , null); 

 但郁悶的發(fā)現(xiàn)其實action雖然異步了,但那些事件還是順序觸發(fā)的,根本不是并發(fā)觸發(fā)。無奈還是寫那個蛋疼的foreach語句。順便提到一句那個foreach中類型寫全了,別用var,因為var會自動推斷為Delegate。當(dāng)然你自己再轉(zhuǎn)換下也行,如果你喜歡的話。

我把代碼貼出來的目的是找bug,還望各位大神多多指出其中問題。各種都可以,包括性能方面的。(我現(xiàn)在最懷疑的就是這里面到處異步,用線程池的資源會不會出現(xiàn)性能問題,畢竟線程有時候就是坑爹的) 

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    發(fā)表評論 查看所有評論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)