亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 網站 > WEB開發 > 正文

C#編寫高性能網絡服務器(源碼)

2024-04-27 15:14:50
字體:
來源:轉載
供稿:網友

C#編寫高性能網絡服務器(源碼)http://www.cnblogs.com/zhoutk/archive/2012/12/26/2833495.html

最近有項目要做一個高性能網絡服務器,決定下功夫搞定完成端口(IOCP),最終花了一個星期終于把它弄清楚了,并用C++寫了一個版本,效率很不錯。

但,從項目的總體需求來考慮,最終決定上.net平臺,因此又花了一天一夜弄出了一個C#版,在這與大家分享。

一些心得體會:

1、在C#中,不用去面對完成端口的操作系統內核對象,Microsoft已經為我們提供了SocketAsyncEventArgs類,它封裝了IOCP的使用。請參考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1。

2、我的SocketAsyncEventArgsPool類使用List對象來存儲對客戶端來通信的SocketAsyncEventArgs對象,它相當于直接使用內核對象時的IoContext。我這樣設計比用堆棧來實現的好處理是,我可以在SocketAsyncEventArgsPool池中找到任何一個與服務器連接的客戶,主動向它發信息。而用堆棧來實現的話,要主動給客戶發信息,則還要設計一個結構來存儲已連接上服務器的客戶。

3、對每一個客戶端不管還發送還是接收,我使用同一個SocketAsyncEventArgs對象,對每一個客戶端來說,通信是同步進行的,也就是說服務器高度保證同一個客戶連接上要么在投遞發送請求,并等待;或者是在投遞接收請求,等待中。本例只做echo服務器,還未考慮由服務器主動向客戶發送信息。

4、SocketAsyncEventArgs的UserToken被直接設定為被接受的客戶端Socket。

5、沒有使用BufferManager 類,因為我在初始化時給每一個SocketAsyncEventArgsPool中的對象分配一個緩沖區,發送時使用Arrary.Copy來進行字符拷貝,不去改變緩沖區的位置,只改變使用的長度,因此在下次投遞接收請求時恢復緩沖區長度就可以了!如果要主動給客戶發信息的話,可以new一個SocketAsyncEventArgs對象,或者在初始化中建立幾個來專門用于主動發送信息,因為這種需求一般是進行信息群發,建立一個對象可以用于很多次信息發送,總體來看,這種花銷不大,還減去了字符拷貝和消耗。

6、測試結果:(在我的筆記本上時行的,我的本本是T420 I7 8G內存)

100客戶 100,000(十萬次)不間斷的發送接收數據(發送和接收之間沒有Sleep,就一個一循環,不斷的發送與接收)耗時3004.6325 秒完成總共 10,000,000 一千萬次訪問平均每分完成 199,691.6 次發送與接收平均每秒完成 3,328.2 次發送與接收

整個運行過程中,內存消耗在開始兩三分種后就保持穩定不再增漲。

看了一下對每個客戶端的延遲最多不超過2毫秒,CPU占用在8%左右。

7、下載地址:http://download.csdn.net/detail/ztk12/4928644

8、源碼:

IoContextPool.csusing System;using System.Collections.Generic;using System.Text;using System.Net.Sockets;namespace IocpServer{    /// <summary>    /// 與每個客戶Socket相關聯,進行Send和Receive投遞時所需要的參數    /// </summary>    internal sealed class IoContextPool    {        List<SocketAsyncEventArgs> pool;        //為每一個Socket客戶端分配一個SocketAsyncEventArgs,用一個List管理,在程序啟動時建立。        Int32 capacity;                         //pool對象池的容量        Int32 boundary;                         //已分配和未分配對象的邊界,大的是已經分配的,小的是未分配的        internal IoContextPool(Int32 capacity)        {            this.pool = new List<SocketAsyncEventArgs>(capacity);            this.boundary = 0;            this.capacity = capacity;        }        /// <summary>        /// 往pool對象池中增加新建立的對象,因為這個程序在啟動時會建立好所有對象,        /// 故這個方法只在初始化時會被調用,因此,沒有加鎖。        /// </summary>        /// <param name="arg"></param>        /// <returns></returns>        internal bool Add(SocketAsyncEventArgs arg)        {            if (arg != null && pool.Count < capacity)            {                pool.Add(arg);                boundary++;                return true;            }            else                return false;        }        /// <summary>        /// 取出集合中指定對象,內部使用        /// </summary>        /// <param name="index"></param>        /// <returns></returns>        //internal SocketAsyncEventArgs Get(int index)        //{        //    if (index >= 0 && index < capacity)        //        return pool[index];        //    else        //        return null;        //}        /// <summary>        /// 從對象池中取出一個對象,交給一個socket來進行投遞請求操作        /// </summary>        /// <returns></returns>        internal SocketAsyncEventArgs Pop()        {            lock (this.pool)            {                if (boundary > 0)                {                    --boundary;                    return pool[boundary];                }                else                    return null;            }        }        /// <summary>        /// 一個socket客戶斷開,與其相關的IoContext被釋放,重新投入Pool中,備用。        /// </summary>        /// <param name="arg"></param>        /// <returns></returns>        internal bool Push(SocketAsyncEventArgs arg)        {            if (arg != null)            {                lock (this.pool)                {                    int index = this.pool.IndexOf(arg, boundary);  //找出被斷開的客戶,此處一定能查到,因此index不可能為-1,必定要大于0。                    if (index == boundary)         //正好是邊界元素                        boundary++;                    else                    {                        this.pool[index] = this.pool[boundary];     //將斷開客戶移到邊界上,邊界右移                        this.pool[boundary++] = arg;                    }                }                return true;            }            else                return false;        }    }}

IoServer.csusing System;using System.Collections.Generic;using System.Text;using System.Net.Sockets;using System.Threading;using System.Net;namespace IocpServer{    /// <summary>    /// 基于SocketAsyncEventArgs 實現 IOCP 服務器    /// </summary>    internal sealed class IoServer    {        /// <summary>        /// 監聽Socket,用于接受客戶端的連接請求        /// </summary>        PRivate Socket listenSocket;        /// <summary>        /// 用于服務器執行的互斥同步對象        /// </summary>        private static Mutex mutex = new Mutex();        /// <summary>        /// 用于每個I/O Socket操作的緩沖區大小        /// </summary>        private Int32 bufferSize;        /// <summary>        /// 服務器上連接的客戶端總數        /// </summary>        private Int32 numConnectedSockets;        /// <summary>        /// 服務器能接受的最大連接數量        /// </summary>        private Int32 numConnections;        /// <summary>        /// 完成端口上進行投遞所用的IoContext對象池        /// </summary>        private IoContextPool ioContextPool;        public MainForm mainForm;        /// <summary>        /// 構造函數,建立一個未初始化的服務器實例        /// </summary>        /// <param name="numConnections">服務器的最大連接數據</param>        /// <param name="bufferSize"></param>        internal IoServer(Int32 numConnections, Int32 bufferSize)        {            this.numConnectedSockets = 0;            this.numConnections = numConnections;            this.bufferSize = bufferSize;            this.ioContextPool = new IoContextPool(numConnections);            // 為IoContextPool預分配SocketAsyncEventArgs對象            for (Int32 i = 0; i < this.numConnections; i++)            {                SocketAsyncEventArgs ioContext = new SocketAsyncEventArgs();                ioContext.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);                ioContext.SetBuffer(new Byte[this.bufferSize], 0, this.bufferSize);                // 將預分配的對象加入SocketAsyncEventArgs對象池中                this.ioContextPool.Add(ioContext);            }        }        /// <summary>        /// 當Socket上的發送或接收請求被完成時,調用此函數        /// </summary>        /// <param name="sender">激發事件的對象</param>        /// <param name="e">與發送或接收完成操作相關聯的SocketAsyncEventArg對象</param>        private void OnIOCompleted(object sender, SocketAsyncEventArgs e)        {            // Determine which type of Operation just completed and call the associated handler.            switch (e.LastOperation)            {                case SocketAsyncOperation.Receive:                    this.ProcessReceive(e);                    break;                case SocketAsyncOperation.Send:                    this.ProcessSend(e);                    break;                default:                    throw new ArgumentException("The last operation completed on the socket was not a receive or send");            }        }        /// <summary>        ///接收完成時處理函數        /// </summary>        /// <param name="e">與接收完成操作相關聯的SocketAsyncEventArg對象</param>        private void ProcessReceive(SocketAsyncEventArgs e)        {            // 檢查遠程主機是否關閉連接            if (e.BytesTransferred > 0)            {                if (e.SocketError == SocketError.Success)                {                    Socket s = (Socket)e.UserToken;                    //判斷所有需接收的數據是否已經完成                    if (s.Available == 0)                    {                        // 設置發送數據                        Array.Copy(e.Buffer, 0, e.Buffer, e.BytesTransferred, e.BytesTransferred);                        e.SetBuffer(e.Offset, e.BytesTransferred * 2);                        if (!s.SendAsync(e))        //投遞發送請求,這個函數有可能同步發送出去,這時返回false,并且不會引發SocketAsyncEventArgs.Completed事件                        {                            // 同步發送時處理發送完成事件                            this.ProcessSend(e);                        }                    }                    else if (!s.ReceiveAsync(e))    //為接收下一段數據,投遞接收請求,這個函數有可能同步完成,這時返回false,并且不會引發SocketAsyncEventArgs.Completed事件                    {                        // 同步接收時處理接收完成事件                        this.ProcessReceive(e);                    }                }                else                {                    this.ProcessError(e);                }            }            else            {                this.CloseClientSocket(e);            }        }        /// <summary>        /// 發送完成時處理函數        /// </summary>        /// <param name="e">與發送完成操作相關聯的SocketAsyncEventArg對象</param>        private void ProcessSend(SocketAsyncEventArgs e)        {            if (e.SocketError == SocketError.Success)            {                Socket s = (Socket)e.UserToken;                //接收時根據接收的字節數收縮了緩沖區的大小,因此投遞接收請求時,恢復緩沖區大小                e.SetBuffer(0, bufferSize);                if (!s.ReceiveAsync(e))     //投遞接收請求                {                    // 同步接收時處理接收完成事件                    this.ProcessReceive(e);                }            }            else            {                this.ProcessError(e);            }        }        /// <summary>        /// 處理socket錯誤        /// </summary>        /// <param name="e"></param>        private void ProcessError(SocketAsyncEventArgs e)        {            Socket s = e.UserToken as Socket;            IPEndPoint localEp = s.LocalEndPoint as IPEndPoint;            this.CloseClientSocket(s, e);            string outStr = String.Format("套接字錯誤 {0}, IP {1}, 操作 {2}。", (Int32)e.SocketError, localEp, e.LastOperation);            mainForm.Invoke(mainForm.setlistboxcallback, outStr);            //Console.WriteLine("Socket error {0} on endpoint {1} during {2}.", (Int32)e.SocketError, localEp, e.LastOperation);        }        /// <summary>        /// 關閉socket連接        /// </summary>        /// <param name="e">SocketAsyncEventArg associated with the completed send/receive operation.</param>        private void CloseClientSocket(SocketAsyncEventArgs e)        {            Socket s = e.UserToken as Socket;            this.CloseClientSocket(s, e);        }        private void CloseClientSocket(Socket s, SocketAsyncEventArgs e)        {            Interlocked.Decrement(ref this.numConnectedSockets);            // SocketAsyncEventArg 對象被釋放,壓入可重用隊列。            this.ioContextPool.Push(e);                        string outStr = String.Format("客戶 {0} 斷開, 共有 {1} 個連接。", s.RemoteEndPoint.ToString(), this.numConnectedSockets);            mainForm.Invoke(mainForm.setlistboxcallback, outStr);                        //Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", this.numConnectedSockets);            try            {                s.Shutdown(SocketShutdown.Send);            }            catch (Exception)            {                // Throw if client has closed, so it is not necessary to catch.            }            finally            {                s.Close();            }        }        /// <summary>        /// accept 操作完成時回調函數        /// </summary>        /// <param name="sender">Object who raised the event.</param>        /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>        private void OnAcceptCompleted(object sender, SocketAsyncEventArgs e)        {            this.ProcessAccept(e);        }        /// <summary>        /// 監聽Socket接受處理        /// </summary>        /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>        private void ProcessAccept(SocketAsyncEventArgs e)        {            Socket s = e.AcceptSocket;            if (s.Connected)            {                try                {                    SocketAsyncEventArgs ioContext = this.ioContextPool.Pop();                    if (ioContext != null)                    {                        // 從接受的客戶端連接中取數據配置ioContext                        ioContext.UserToken = s;                        Interlocked.Increment(ref this.numConnectedSockets);                        string outStr = String.Format("客戶 {0} 連入, 共有 {1} 個連接。",  s.RemoteEndPoint.ToString(),this.numConnectedSockets);                        mainForm.Invoke(mainForm.setlistboxcallback,outStr);                        //Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",                            //this.numConnectedSockets);                        if (!s.ReceiveAsync(ioContext))                        {                            this.ProcessReceive(ioContext);                        }                    }                    else        //已經達到最大客戶連接數量,在這接受連接,發送“連接已經達到最大數”,然后斷開連接                    {                        s.Send(Encoding.Default.GetBytes("連接已經達到最大數!"));                        string outStr = String.Format("連接已滿,拒絕 {0} 的連接。", s.RemoteEndPoint);                        mainForm.Invoke(mainForm.setlistboxcallback, outStr);                        s.Close();                   }                }                catch (SocketException ex)                {                    Socket token = e.UserToken as Socket;                    string outStr = String.Format("接收客戶 {0} 數據出錯, 異常信息: {1} 。", token.RemoteEndPoint, ex.ToString());                    mainForm.Invoke(mainForm.setlistboxcallback, outStr);                    //Console.WriteLine("Error when processing data received from {0}:/r/n{1}", token.RemoteEndPoint, ex.ToString());                }                catch (Exception ex)                {                    mainForm.Invoke(mainForm.setlistboxcallback, "異常:" + ex.ToString());                }                // 投遞下一個接受請求                this.StartAccept(e);            }        }        /// <summary>        /// 從客戶端開始接受一個連接操作        /// </summary>        /// <param name="acceptEventArg">The context object to use when issuing         /// the accept operation on the server's listening socket.</param>        private void StartAccept(SocketAsyncEventArgs acceptEventArg)        {            if (acceptEventArg == null)            {                acceptEventArg = new SocketAsyncEventArgs();                acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);            }            else            {                // 重用前進行對象清理                acceptEventArg.AcceptSocket = null;            }            if (!this.listenSocket.AcceptAsync(acceptEventArg))            {                this.ProcessAccept(acceptEventArg);            }        }        /// <summary>        /// 啟動服務,開始監聽        /// </summary>        /// <param name="port">Port where the server will listen for connection requests.</param>        internal void Start(Int32 port)        {            // 獲得主機相關信息            IPAddress[] addressList = Dns.GetHostEntry(Environment.MachineName).AddressList;            IPEndPoint localEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);            // 創建監聽socket            this.listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);            this.listenSocket.ReceiveBufferSize = this.bufferSize;            this.listenSocket.SendBufferSize = this.bufferSize;            if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6)            {                // 配置監聽socket為 dual-mode (IPv4 & IPv6)                 // 27 is equivalent to IPV6_V6ONLY socket option in the winsock snippet below,                this.listenSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);                this.listenSocket.Bind(new IPEndPoint(IPAddress.IPv6Any, localEndPoint.Port));            }            else            {                this.listenSocket.Bind(localEndPoint);            }            // 開始監聽            this.listenSocket.Listen(this.numConnections);            // 在監聽Socket上投遞一個接受請求。            this.StartAccept(null);            // Blocks the current thread to receive incoming messages.            mutex.WaitOne();        }        /// <summary>        /// 停止服務        /// </summary>        internal void Stop()        {            this.listenSocket.Close();            mutex.ReleaseMutex();        }    }}


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人sm免费视频| 伊人久久大香线蕉av一区二区| 久久久久久久一区二区三区| 国产精品91久久久| 亚洲国产97在线精品一区| 日韩一区二区av| 海角国产乱辈乱精品视频| 久久中文字幕一区| 国产成人欧美在线观看| 欧美精品video| 日韩精品一区二区三区第95| 欧美一区二区三区免费观看| 国产精品18久久久久久首页狼| 国产精品丝袜久久久久久高清| 日本欧美黄网站| 国产精品一区二区三区免费视频| 福利一区福利二区微拍刺激| 欧美劲爆第一页| 色www亚洲国产张柏芝| 在线成人激情视频| 欧美激情在线狂野欧美精品| 亚洲第一福利在线观看| 亚洲成色777777在线观看影院| 欧美老女人在线视频| 色综合五月天导航| 欧美精品videosex牲欧美| 亚洲美女视频网站| 国内精品中文字幕| 国产成人极品视频| 日韩国产中文字幕| 欧美人与性动交a欧美精品| 日韩av在线网址| 欧美日韩国产一中文字不卡| 国产精品久久999| 欧美一区视频在线| 国产91精品久久久久| 欧美激情18p| 欧美国产第二页| 国产精品扒开腿做爽爽爽男男| 国产精自产拍久久久久久| 欧美极品少妇xxxxx| 色一情一乱一区二区| 欧美电影电视剧在线观看| 国产视频欧美视频| 欧美成人亚洲成人| 国产精品久久久久久久久久久新郎| 国模吧一区二区| 欧美精品电影在线| 日韩av三级在线观看| 亚洲天堂精品在线| 国内精品美女av在线播放| 在线观看91久久久久久| 91国偷自产一区二区三区的观看方式| 日韩av影视综合网| 懂色aⅴ精品一区二区三区蜜月| 一区二区三区美女xx视频| 日韩av片电影专区| 91精品国产综合久久久久久久久| 亚洲一区二区三区在线免费观看| 久久久精品一区二区| 亚洲自拍av在线| 色偷偷91综合久久噜噜| 亚洲综合av影视| 国产成人精品视频在线| 久久国产一区二区三区| 国产精品久久av| 国产一区二区色| 日韩精品电影网| 午夜精品三级视频福利| 国产999在线| 97**国产露脸精品国产| 欧美极品少妇xxxxⅹ免费视频| 亚洲欧美激情一区| 亚洲女人天堂网| 国产精品永久免费观看| xxxxx91麻豆| 欧美日韩中文在线观看| 欧美乱人伦中文字幕在线| 国产欧美精品久久久| 欧美另类在线观看| 日韩av网站电影| 亚洲国产精品99| 在线观看国产成人av片| 亚洲精品久久久久中文字幕二区| 久久成人精品电影| 亚洲成人黄色在线观看| 国产综合久久久久| 欧美成人国产va精品日本一级| 欧美一级淫片videoshd| 国产精品永久免费视频| 亚洲国产精品电影在线观看| 精品美女久久久久久免费| 中文亚洲视频在线| 亚洲片在线观看| 亚洲影视中文字幕| 91久久精品日日躁夜夜躁国产| 中文字幕自拍vr一区二区三区| 亚洲视频一区二区三区| 国模视频一区二区三区| 国产欧美精品在线播放| 中文字幕日韩精品有码视频| 国产亚洲a∨片在线观看| 久久精品成人动漫| 黑人狂躁日本妞一区二区三区| 成人高h视频在线| 久久久999精品免费| 精品露脸国产偷人在视频| 成人网在线视频| 亚洲欧洲午夜一线一品| 欧美高清第一页| 色多多国产成人永久免费网站| 亚洲美女av在线| 亚洲高清福利视频| 久久久av免费| 欧美色videos| 亚洲电影中文字幕| 人人爽久久涩噜噜噜网站| 国产精品成人免费电影| 亚洲精品国产精品国自产在线| 亚洲美女中文字幕| 国产+成+人+亚洲欧洲| 91精品国产九九九久久久亚洲| 欧美极品少妇xxxxⅹ喷水| 久久久噜噜噜久久久| 欧美电影免费观看大全| 国产精品免费一区| 日韩av在线直播| 在线观看欧美日韩国产| 国产亚洲美女精品久久久| 91在线观看免费高清完整版在线观看| 中文字幕日韩有码| 亚洲精品在线视频| 欧美日韩中文字幕综合视频| 在线午夜精品自拍| 精品国产一区二区在线| 在线视频免费一区二区| 欧美整片在线观看| 亚洲精品视频免费在线观看| 国产精品久久久久久久久影视| 亚洲精品www久久久| 成人免费高清完整版在线观看| 2019中文字幕在线免费观看| 欧美激情精品久久久久久久变态| 亚洲美女av在线| 日韩中文字幕精品视频| 亚洲精品成人网| 亚洲一区二区三区四区视频| 久久久综合av| 国产91精品不卡视频| 欧美极品少妇xxxxⅹ裸体艺术| 久久综合免费视频| 国产日本欧美在线观看| 91中文在线观看| 久久中文久久字幕| 亚洲天堂免费观看| 中文字幕精品一区久久久久| 亚洲国产精品视频在线观看| 欧美综合一区第一页| 国产成人精品一区二区| 亚洲综合精品一区二区| 日韩精品福利网站| 不卡伊人av在线播放| 成人免费观看49www在线观看| 欧美一区二区三区免费视|