最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C#網(wǎng)絡(luò)編程詳解篇

 更新時(shí)間:2017年01月23日 00:05:30   作者:蘑菇先生  
在現(xiàn)今軟件開發(fā)中,網(wǎng)絡(luò)編程是非常重要的一部分,本文簡(jiǎn)要介紹下網(wǎng)絡(luò)編程的概念和實(shí)踐,需要的朋友可以參考下

閱讀目錄:

基礎(chǔ)
Socket編程
多線程并發(fā)
阻塞式同步IO

基礎(chǔ)
在現(xiàn)今軟件開發(fā)中,網(wǎng)絡(luò)編程是非常重要的一部分,本文簡(jiǎn)要介紹下網(wǎng)絡(luò)編程的概念和實(shí)踐。
Socket是一種網(wǎng)絡(luò)編程接口,它是對(duì)傳輸層TCP、UDP通信協(xié)議的一層封裝,通過友好的API暴露出去,方便在進(jìn)程或多臺(tái)機(jī)器間進(jìn)行網(wǎng)絡(luò)通信。

Socket編程

在網(wǎng)絡(luò)編程中分客戶端和服務(wù)端兩種角色,比如通過打開瀏覽器訪問到掛在Web軟件上的網(wǎng)頁,從程序角度上來看,即客戶端(瀏覽器)發(fā)起了一個(gè)Socket請(qǐng)求到服務(wù)器端,服務(wù)器把網(wǎng)頁內(nèi)容返回到瀏覽器解析后展示。在客戶端和服務(wù)端數(shù)據(jù)通信前,會(huì)進(jìn)行三次確認(rèn)才會(huì)正式建立連接,也即是三次握手。

  1. 客戶端發(fā)送消息詢問服務(wù)端是否準(zhǔn)備好
  2. 服務(wù)端回應(yīng)我準(zhǔn)備好了,你呢準(zhǔn)備好了嗎
  3. 客戶端回應(yīng)服務(wù)端我也準(zhǔn)備好了,可以通信了

TCP/IP協(xié)議是網(wǎng)絡(luò)間通信的基礎(chǔ)協(xié)議,在不同編程語言及不同操作系統(tǒng)下暴露的Socket接口用法也大同小異,僅是其內(nèi)部實(shí)現(xiàn)有所不同,比如Linux下的epoll和windows下的IOCP。

服務(wù)端
  • 實(shí)例化Socket
  • 把公共地址端口綁定操作系統(tǒng)上
  • 開始監(jiān)聽綁定的端口
  • 等待客戶端連接
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 6389);
      Socket listenSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
      listenSocket.Bind(ip);
      listenSocket.Listen(100);
      listenSocket.Accept();

listen函數(shù)中有個(gè)int類型參數(shù),它表示最大等待處理連接的數(shù)量,表示已建立連接但還未處理的數(shù)量,每調(diào)用Accept函數(shù)一下即從這個(gè)等待隊(duì)列中拿出一個(gè)連接。 通常服務(wù)端要服務(wù)多個(gè)客戶端請(qǐng)求的連接,所以會(huì)循環(huán)從等待隊(duì)列中拿出連接,進(jìn)行接收發(fā)送。

while (true) 
      { 
        var accept= listenSocket.Accept();
        accept.Receive(); 
        accept.Send(); 
      }

多線程并發(fā)
上面的服務(wù)端程序處理接收和發(fā)送消息都是在當(dāng)前線程下完成的,這意味著要處理完一個(gè)客戶端連接后才能去處理下一個(gè)連接,如果當(dāng)前連接是進(jìn)行數(shù)據(jù)庫或者文件讀取寫入等IO操作,那會(huì)極大浪費(fèi)服務(wù)器的CPU資源,降低了服務(wù)器吞吐量。

while (true)
      {
        var accept = listenSocket.Accept();
        ThreadPool.QueueUserWorkItem((obj) =>
        {
          byte[] receive = new byte[100];
          accept.Receive(receive);
          byte[] send = new byte[100];
          accept.Send(receive);
        });
      }

如例子中,當(dāng)監(jiān)聽到有新連接請(qǐng)求過來時(shí),調(diào)用Accept()取出當(dāng)前連接的socket,使用新的線程去處理接收和發(fā)送信息,這樣服務(wù)端就能實(shí)現(xiàn)并發(fā)處理多個(gè)客戶端了。 上述代碼中,在高并發(fā)下其實(shí)是有問題的,如果客戶端連接請(qǐng)求成千上萬個(gè),那線程數(shù)量也會(huì)有這么多,每個(gè)線程的??臻g都需要消耗部分內(nèi)存,再加上線程上下文切換,容易導(dǎo)致服務(wù)器負(fù)載過高,吞吐量大大下降,嚴(yán)重時(shí)會(huì)引起宕機(jī)。 當(dāng)前例子中使用系統(tǒng)ThreadPool的話,線程數(shù)量會(huì)固定在一個(gè)數(shù)量上,默認(rèn)是1000,不會(huì)無限制開線程,會(huì)把處理超出線程數(shù)量的請(qǐng)求放到線程池中的隊(duì)列上面。
在unix下類似的實(shí)現(xiàn)有2種:

fork一個(gè)新進(jìn)程去處理客戶端的連接:

var connfd = Accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); 
var m = fork(); 
if(m == 0) 
{
 //do something 
}

創(chuàng)建一個(gè)新的線程處理限流:

var *clientsockfd = accept(serversockfd,(struct sockaddr *)&clientaddress, (socklent *)&clientlen);
 if(pthreadcreate(&thread, NULL, recdata, clientsockfd)!=0) 
{ //do something 
}

阻塞式同步IO
上述例子中使用的即是該模型,使用起來簡(jiǎn)單方便。

while (true)
      {
        var accept = listenSocket.Accept();
        byte[] receive = new byte[100];
        accept.Receive(receive);
        byte[] send = new byte[100];
        accept.Send(receive);
      }

從調(diào)用Receive函數(shù)起到接受到客戶端發(fā)過來的數(shù)據(jù)期間,該函數(shù)會(huì)一直阻塞等待著,這個(gè)阻塞期間處理流程如下:

  1. 客戶端發(fā)送數(shù)據(jù)
  2. 通過廣域網(wǎng)局域網(wǎng)發(fā)送到服務(wù)端機(jī)器網(wǎng)卡緩沖區(qū)上
  3. 網(wǎng)卡驅(qū)動(dòng)對(duì)CPU發(fā)送中斷指令
  4. CPU把數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)
  5. CPU再把內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝用戶緩沖區(qū),上面的receive字節(jié)數(shù)組。

至此處理成功,開始處理下一個(gè)連接請(qǐng)求。 調(diào)用發(fā)送函數(shù)同樣會(huì)阻塞在當(dāng)前,然后把用戶緩沖區(qū)(send字節(jié)數(shù)組)數(shù)據(jù)拷貝到內(nèi)核中TCP發(fā)送緩沖區(qū)中。 TCP的發(fā)送緩沖區(qū)也有一定的大小限制,如果發(fā)送的數(shù)據(jù)大于該限制,send函數(shù)會(huì)一直等待發(fā)送緩沖區(qū)有空閑時(shí)完全拷貝完才會(huì)返回,繼續(xù)處理后續(xù)連接請(qǐng)求。

異步IO
上篇提到用多線程處理多個(gè)阻塞同步IO而實(shí)現(xiàn)并發(fā)服務(wù)端,這種模式在連接數(shù)量比較小的時(shí)候非常適合,一旦連接過多,性能會(huì)急速下降。 在大多數(shù)服務(wù)端網(wǎng)絡(luò)軟件中會(huì)采用一種異步IO的方式來提高性能。

同步IO方式:連接Receive請(qǐng)求->等待->等待->接收成功
異步IO方式:連接Receive請(qǐng)求->立即返回->事件或回調(diào)通知
采用異步IO方式,意味著單線程可以處理多個(gè)請(qǐng)求了,連接發(fā)起一個(gè)Receive請(qǐng)求后,當(dāng)前線程可以立即去做別的事情,當(dāng)數(shù)據(jù)接收完畢通知線程處理即可。
其數(shù)據(jù)接收分2部分:

數(shù)據(jù)從別的機(jī)器發(fā)送內(nèi)核緩沖區(qū)
內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū)
第二部分示例代碼:

byte[] msg = new byte[256]; socket.Receive(msg);

介紹這2部分的目的是方便區(qū)分其他幾種方式。 對(duì)于用戶程序來說,同步IO和異步IO的區(qū)別在于第二部分是否需要等待。

非阻塞式同步IO
非阻塞式同步IO,由同步IO延伸出來,把這個(gè)名詞拆分成2部分描述:

  • 非阻塞式,指的是上節(jié)"數(shù)據(jù)從別的機(jī)器發(fā)送內(nèi)核緩沖區(qū)"部分是非阻塞的。
  • 同步IO,指的是上節(jié)"內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū)"部分是等待的。

既然是第一部分是非阻塞的,那就需要一種方法得知什么時(shí)候內(nèi)核緩沖區(qū)是OK的。 設(shè)置非阻塞模式后,在連接調(diào)用Receive方法時(shí),會(huì)立即返回一個(gè)標(biāo)記,告知用戶程序內(nèi)核緩存區(qū)有沒有數(shù)據(jù),如果有數(shù)據(jù)開始進(jìn)行第二部分操作,從內(nèi)核緩沖區(qū)拷貝到用戶程序緩沖區(qū)。 由于系統(tǒng)會(huì)返回個(gè)標(biāo)記,那可以通過輪詢方式來判斷內(nèi)核緩沖區(qū)是否OK。

設(shè)置非阻塞模式參考代碼:

SocketInformation sif=new SocketInformation();
sif.Options=SocketInformationOptions.NonBlocking;
sif.ProtocolInformation = new byte[24];
Socket socket = new Socket(sif);

輪詢參考代碼:

while(true) 
{
byte[] msg = new byte[256];
var temp = socket.Receive(msg);
if (temp=="OK"){
//do something
}else{ continue }
}

這種方式近乎淘汰了,了解即可。

基于回調(diào)的異步IO
上面介紹過:

異步IO方式:連接Receive請(qǐng)求->立即返回->事件或回調(diào)通知
當(dāng)回調(diào)到執(zhí)行時(shí),數(shù)據(jù)已經(jīng)在用戶程序緩沖區(qū)已經(jīng)準(zhǔn)備好了,在回調(diào)代碼中對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行相應(yīng)的邏輯即可。

發(fā)出接收請(qǐng)求:

static byte[] msg = new byte[256]; 
var temp = socket.BeginReceive(msg, 0, msg.Length, 0, new AsyncCallback(ReadCallback), socket);

回調(diào)函數(shù)中對(duì)數(shù)據(jù)做處理:

public static void ReadCallback(IAsyncResult ar) 
{ 
var socket = (Socket)ar.AsyncState;
 int read = socket.EndReceive(ar);
DoSomething(msg); 
socket.BeginReceive(msg, 0, msg.Length, 0, new AsyncCallback(Read_Callback), socket);
}

當(dāng)回調(diào)函數(shù)執(zhí)行時(shí),表示數(shù)據(jù)已經(jīng)準(zhǔn)備好,需要先結(jié)束接收請(qǐng)求EndReceive,以便第二次發(fā)出接收請(qǐng)求。 在服務(wù)端程序中要處理多個(gè)客戶端的接收,再次發(fā)出BeginReceive接收數(shù)據(jù)請(qǐng)求即可。

這里的回調(diào)函數(shù)是在另外一個(gè)線程的觸發(fā),必要時(shí)要對(duì)數(shù)據(jù)加鎖防止數(shù)據(jù)競(jìng)爭(zhēng):

Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

針對(duì)C#網(wǎng)絡(luò)編程的介紹就到這了,具體的大家可以查看腳本之家之前發(fā)布的文章。

相關(guān)文章

  • Unity實(shí)現(xiàn)簡(jiǎn)單的多人聊天工具

    Unity實(shí)現(xiàn)簡(jiǎn)單的多人聊天工具

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)簡(jiǎn)單的多人聊天工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#的this關(guān)鍵字的2種用法

    C#的this關(guān)鍵字的2種用法

    這篇文章主要給大家分享的是C#的this關(guān)鍵字的2種用法,在使用C#的過程中,發(fā)現(xiàn)this關(guān)鍵是比較少用的,但是在下面這二個(gè)場(chǎng)合下是必須要使用的,不使用它是解決不了問題。下面我們就來看看文章的具體內(nèi)容吧
    2021-10-10
  • C#實(shí)現(xiàn)動(dòng)態(tài)生成表格的方法

    C#實(shí)現(xiàn)動(dòng)態(tài)生成表格的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)動(dòng)態(tài)生成表格的方法,是C#程序設(shè)計(jì)中非常實(shí)用的技巧,需要的朋友可以參考下
    2014-09-09
  • C#中圖片.BYTE[]和base64string的轉(zhuǎn)換方法

    C#中圖片.BYTE[]和base64string的轉(zhuǎn)換方法

    下面小編就為大家?guī)硪黄狢#中圖片.BYTE[]和base64string的轉(zhuǎn)換方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效

    Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • 基于C# 寫一個(gè) Redis 數(shù)據(jù)同步小工具

    基于C# 寫一個(gè) Redis 數(shù)據(jù)同步小工具

    Redis支持主從同步。數(shù)據(jù)可以從主服務(wù)器向任意數(shù)量的從服務(wù)器上同步,從服務(wù)器可以是關(guān)聯(lián)其他從服務(wù)器的主服務(wù)器。這篇文章主要介紹了用 C# 寫一個(gè) Redis 數(shù)據(jù)同步小工具,需要的朋友可以參考下
    2020-02-02
  • 淺談C#六大設(shè)計(jì)原則

    淺談C#六大設(shè)計(jì)原則

    這篇文章主要介紹了C#六大設(shè)計(jì)原則的相關(guān)內(nèi)容,文中代碼非常細(xì)致,供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C#實(shí)現(xiàn)treeview綁定的方法

    C#實(shí)現(xiàn)treeview綁定的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)treeview綁定的方法,包括datatable的獲取與節(jié)點(diǎn)的操作,具有一定的參考價(jià)值,需要的朋友可以參考下
    2014-12-12
  • C#條件拼接Expression<Func<T, bool>>的使用

    C#條件拼接Expression<Func<T, bool>>的使用

    本文主要介紹了C#條件拼接Expression<Func<T, bool>>的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#生成不重復(fù)隨機(jī)字符串類

    C#生成不重復(fù)隨機(jī)字符串類

    這篇文章主要介紹了C#生成不重復(fù)隨機(jī)字符串類,涉及C#隨機(jī)數(shù)與字符串的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03

最新評(píng)論

体育| 大英县| 郁南县| 丽江市| 朝阳区| 运城市| 长海县| 常熟市| 桐城市| 林口县| 河间市| 新宾| 运城市| 玛纳斯县| 莲花县| 东港市| 嘉峪关市| 枣庄市| 三明市| 淮安市| 怀安县| 共和县| 汝州市| 怀集县| 北安市| 宜川县| 石门县| 页游| 郴州市| 天镇县| 九龙县| 丰县| 自贡市| 辛集市| 潜江市| 监利县| 淅川县| 永春县| 黎平县| 晋州市| 高安市|