前言
成都創(chuàng)新互聯(lián)是專業(yè)的洪雅網(wǎng)站建設(shè)公司,洪雅接單;提供成都網(wǎng)站設(shè)計、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行洪雅網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!socket是軟件之間通訊最常用的一種方式。c#實現(xiàn)socket通訊有很多中方法,其中效率最高就是異步通訊。
異步通訊實際是利用windows完成端口(IOCP)來處理的,關(guān)于完成端口實現(xiàn)原理,大家可以參考網(wǎng)上文章。
我這里想強調(diào)的是采用完成端口機制的異步通訊是windows下效率最高的通訊方式,沒有之一!
異步通訊比同步通訊處理要難很多,代碼編寫中會遇到許多“坑“。如果沒有經(jīng)驗,很難完成。
我搜集了大量資料,完成了對異步socket的封裝。此庫已用穩(wěn)定高效的運行幾個月。
縱觀網(wǎng)上的資料,我還沒有遇到一個滿意的封裝庫。許多文章把數(shù)據(jù)收發(fā)和協(xié)議處理雜糅在一塊,代碼非常難懂,也無法擴展。
在編寫該庫時,避免以上缺陷。將邏輯處理層次化,模塊化!同時實現(xiàn)了高可用性與高性能。
為了使大家對通訊效率有初步了解,先看測試圖。
主機配置情況
百兆帶寬基本占滿,cpu占用40%,我的電腦在空閑時,cpu占用大概20%,也就是說程序占用cpu 20%左右。
這個庫是可擴展的,就是說即使10萬個連接,收發(fā)同樣的數(shù)據(jù),cpu占用基本相同。
庫的結(jié)構(gòu)圖
目標(biāo)
即可作為服務(wù)端(監(jiān)聽)也可以作為客戶端(主動連接)使用。
可以適應(yīng)任何網(wǎng)絡(luò)協(xié)議。收發(fā)的數(shù)據(jù)針對字節(jié)流或一個完整的包。對協(xié)議內(nèi)容不做處理。
高可用性。將復(fù)雜的底層處理封裝,對外接口非常友好。
高性能。大限度優(yōu)化處理。單機可支持?jǐn)?shù)萬連接,收發(fā)速度可達幾百兆bit。
實現(xiàn)思路
網(wǎng)絡(luò)處理邏輯可以分為以下幾個部分:
網(wǎng)絡(luò)監(jiān)聽 可以在多個端口實現(xiàn)監(jiān)聽。負責(zé)生成socket,生成的socket供后續(xù)處理。監(jiān)聽模塊功能比較單一,如有必要,可對監(jiān)聽模塊做進一步優(yōu)化。
主動連接 可以異步或同步的連接對方。連接成功后,對socket的后續(xù)處理,與監(jiān)聽得到的socket完全一樣。注:無論是監(jiān)聽得到的socket,還是連接得到的socket,后續(xù)處理完全一樣。
Socket收發(fā)處理 每個socket對應(yīng)一個收發(fā)實例,socket收發(fā)只針對字節(jié)流處理。收發(fā)時,做了優(yōu)化。比如發(fā)送時,對數(shù)據(jù)做了沾包,提高發(fā)送性能;接收時,一次投遞1K的數(shù)據(jù)。
組包處理 一般數(shù)據(jù)包都有包長度指示;比如 報頭的前倆個字節(jié)表示長度,根據(jù)這個值就可以組成一個完整的包。
NetListener 監(jiān)聽
using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace IocpCore { class NetListener { private Socket listenSocket; public ListenParam _listenParam { get; set; } public event ActionOnAcceptSocket; bool start; NetServer _netServer; public NetListener(NetServer netServer) { _netServer = netServer; } public int _acceptAsyncCount = 0; public bool StartListen() { try { start = true; IPEndPoint listenPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), _listenParam._port); listenSocket = new Socket(listenPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); listenSocket.Bind(listenPoint); listenSocket.Listen(200); Thread thread1 = new Thread(new ThreadStart(NetProcess)); thread1.Start(); StartAccept(); return true; } catch (Exception ex) { NetLogger.Log(string.Format("**監(jiān)聽異常!{0}", ex.Message)); return false; } } AutoResetEvent _acceptEvent = new AutoResetEvent(false); private void NetProcess() { while (start) { DealNewAccept(); _acceptEvent.WaitOne(1000 * 10); } } private void DealNewAccept() { try { if(_acceptAsyncCount <= 10) { StartAccept(); } while (true) { AsyncSocketClient client = _newSocketClientList.GetObj(); if (client == null) break; DealNewAccept(client); } } catch (Exception ex) { NetLogger.Log(string.Format("DealNewAccept 異常 {0}***{1}", ex.Message, ex.StackTrace)); } } private void DealNewAccept(AsyncSocketClient client) { client.SendBufferByteCount = _netServer.SendBufferBytePerClient; OnAcceptSocket?.Invoke(_listenParam, client); } private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs acceptEventArgs) { try { Interlocked.Decrement(ref _acceptAsyncCount); _acceptEvent.Set(); acceptEventArgs.Completed -= AcceptEventArg_Completed; ProcessAccept(acceptEventArgs); } catch (Exception ex) { NetLogger.Log(string.Format("AcceptEventArg_Completed {0}***{1}", ex.Message, ex.StackTrace)); } } public bool StartAccept() { SocketAsyncEventArgs acceptEventArgs = new SocketAsyncEventArgs(); acceptEventArgs.Completed += AcceptEventArg_Completed; bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArgs); Interlocked.Increment(ref _acceptAsyncCount); if (!willRaiseEvent) { Interlocked.Decrement(ref _acceptAsyncCount); _acceptEvent.Set(); acceptEventArgs.Completed -= AcceptEventArg_Completed; ProcessAccept(acceptEventArgs); } return true; } ObjectPool _newSocketClientList = new ObjectPool (); private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs) { try { using (acceptEventArgs) { if (acceptEventArgs.AcceptSocket != null) { AsyncSocketClient client = new AsyncSocketClient(acceptEventArgs.AcceptSocket); client.CreateClientInfo(this); _newSocketClientList.PutObj(client); _acceptEvent.Set(); } } } catch (Exception ex) { NetLogger.Log(string.Format("ProcessAccept {0}***{1}", ex.Message, ex.StackTrace)); } } } }
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。