国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

淺談C#網絡編程(一)

2019-11-14 13:57:32
字體:
來源:轉載
供稿:網友

閱讀目錄:

  1. 基礎
  2. Socket編程
  3. 多線程并發
  4. 阻塞式同步IO

基礎

在現今軟件開發中,網絡編程是非常重要的一部分,本文簡要介紹下網絡編程的概念和實踐。
Socket是一種網絡編程接口,它是對傳輸層TCP、UDP通信協議的一層封裝,通過友好的API暴露出去,方便在進程或多臺機器間進行網絡通信。

Socket編程

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

  1. 客戶端發送消息詢問服務端是否準備好
  2. 服務端回應我準備好了,你呢準備好了嗎
  3. 客戶端回應服務端我也準備好了,可以通信了

TCP/ip協議是網絡間通信的基礎協議,在不同編程語言及不同操作系統下暴露的Socket接口用法也大同小異,僅是其內部實現有所不同,比如linux下的epoll和windows下的IOCP。

服務端

  • 實例化Socket
  • 把公共地址端口綁定操作系統上
  • 開始監聽綁定的端口
  • 等待客戶端連接
            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函數中有個int類型參數,它表示最大等待處理連接的數量,表示已建立連接但還未處理的數量,每調用Accept函數一下即從這個等待隊列中拿出一個連接。 通常服務端要服務多個客戶端請求的連接,所以會循環從等待隊列中拿出連接,進行接收發送。 

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

多線程并發

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

            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);                });            }

如例子中,當監聽到有新連接請求過來時,調用Accept()取出當前連接的socket,使用新的線程去處理接收和發送信息,這樣服務端就能實現并發處理多個客戶端了。 上述代碼中,在高并發下其實是有問題的,如果客戶端連接請求成千上萬個,那線程數量也會有這么多,每個線程的棧空間都需要消耗部分內存,再加上線程上下文切換,容易導致服務器負載過高,吞吐量大大下降,嚴重時會引起宕機。 當前例子中使用系統ThreadPool的話,線程數量會固定在一個數量上,默認是1000,不會無限制開線程,會把處理超出線程數量的請求放到線程池中的隊列上面。

在unix下類似的實現有2種:

fork一個新進程去處理客戶端的連接:

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

創建一個新的線程處理限流:

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

阻塞式同步IO

上述例子中使用的即是該模型,使用起來簡單方便。 

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

從調用Receive函數起到接受到客戶端發過來的數據期間,該函數會一直阻塞等待著,這個阻塞期間處理流程如下:

  1. 客戶端發送數據
  2. 通過廣域網局域網發送到服務端機器網卡緩沖區上
  3. 網卡驅動對CPU發送中斷指令
  4. CPU把數據拷貝到內核緩沖區
  5. CPU再把內核緩沖區的數據拷貝用戶緩沖區,上面的receive字節數組。

至此處理成功,開始處理下一個連接請求。 調用發送函數同樣會阻塞在當前,然后把用戶緩沖區(send字節數組)數據拷貝到內核中TCP發送緩沖區中。 TCP的發送緩沖區也有一定的大小限制,如果發送的數據大于該限制,send函數會一直等待發送緩沖區有空閑時完全拷貝完才會返回,繼續處理后續連接請求。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 昌乐县| 巨野县| 富裕县| 澄江县| 哈密市| 三亚市| 门头沟区| 敦煌市| 洛扎县| 石河子市| 汉阴县| 漠河县| 丁青县| 鹤峰县| 海安县| 岚皋县| 冷水江市| 新昌县| 北宁市| 宜春市| 陇南市| 上栗县| 改则县| 寿光市| 星子县| 抚顺县| 比如县| 枣阳市| 海林市| 翁牛特旗| 平和县| 安阳市| 沅江市| 开封县| 陇川县| 梅河口市| 华坪县| 房山区| 巴林左旗| 乌审旗| 保亭|