目錄
Socket程式設計
首頁 後端開發 C#.Net教程 C#網路程式設計的圖文代碼詳解

C#網路程式設計的圖文代碼詳解

Mar 28, 2017 am 11:20 AM
c# 網路程式設計

在現今軟體開發中,網頁程式設計是非常重要的一部分,本文簡單介紹下網路程式設計的概念與實作,需要的朋友可以參考下

閱讀目錄:

基礎
Socket程式設計
多執行緒並發
阻塞式同步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函数会一直等待发送缓冲区有空闲时完全拷贝完才会返回,继续处理后续连接请求。

异步IO
上篇提到用多线程处理多个阻塞同步IO而实现并发服务端,这种模式在连接数量比较小的时候非常适合,一旦连接过多,性能会急速下降。 在大多数服务端网络软件中会采用一种异步IO的方式来提高性能。

同步IO方式:连接Receive请求->等待->等待->接收成功
异步IO方式:连接Receive请求->立即返回->事件或回调通知
采用异步IO方式,意味着单线程可以处理多个请求了,连接发起一个Receive请求后,当前线程可以立即去做别的事情,当数据接收完毕通知线程处理即可。
其数据接收分2部分:

数据从别的机器发送内核缓冲区
内核缓冲区拷贝到用户缓冲区
第二部分示例代码:

byte[] msg = new byte[256]; socket.Receive(msg);
登入後複製

介绍这2部分的目的是方便区分其他几种方式。 对于用户程序来说,同步IO和异步IO的区别在于第二部分是否需要等待。

非阻塞式同步IO
非阻塞式同步IO,由同步IO延伸出来,把这个名词拆分成2部分描述:

  • 非阻塞式,指的是上节"数据从别的机器发送内核缓冲区"部分是非阻塞的。

  • 同步IO,指的是上节"内核缓冲区拷贝到用户缓冲区"部分是等待的。

既然是第一部分是非阻塞的,那就需要一种方法得知什么时候内核缓冲区是OK的。 设置非阻塞模式后,在连接调用Receive方法时,会立即返回一个标记,告知用户程序内核缓存区有没有数据,如果有数据开始进行第二部分操作,从内核缓冲区拷贝到用户程序缓冲区。 由于系统会返回个标记,那可以通过轮询方式来判断内核缓冲区是否OK。

设置非阻塞模式参考代码:

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 }
}
登入後複製

这种方式近乎淘汰了,了解即可。

基于回调的异步IO
上面介绍过:

异步IO方式:连接Receive请求->立即返回->事件或回调通知
当回调到执行时,数据已经在用户程序缓冲区已经准备好了,在回调代码中对这部分数据进行相应的逻辑即可。

发出接收请求:

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

回调函数中对数据做处理:

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);
}
登入後複製

当回调函数执行时,表示数据已经准备好,需要先结束接收请求EndReceive,以便第二次发出接收请求。 在服务端程序中要处理多个客户端的接收,再次发出BeginReceive接收数据请求即可。

这里的回调函数是在另外一个线程的触发,必要时要对数据加锁防止数据竞争:

Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
登入後複製

以上是C#網路程式設計的圖文代碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1268
29
C# 教程
1248
24
使用 C# 的活動目錄 使用 C# 的活動目錄 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在這裡,我們討論 Active Directory 在 C# 中的介紹和工作原理以及語法和範例。

C# 中的隨機數產生器 C# 中的隨機數產生器 Sep 03, 2024 pm 03:34 PM

C# 隨機數產生器指南。在這裡,我們討論隨機數產生器的工作原理、偽隨機數和安全數的概念。

C# 資料網格視圖 C# 資料網格視圖 Sep 03, 2024 pm 03:32 PM

C# 資料網格視圖指南。在這裡,我們討論如何從 SQL 資料庫或 Excel 檔案載入和匯出資料網格視圖的範例。

C# 中的階乘 C# 中的階乘 Sep 03, 2024 pm 03:34 PM

C# 階乘指南。這裡我們討論 C# 中階乘的介紹以及不同的範例和程式碼實作。

c#多線程和異步的區別 c#多線程和異步的區別 Apr 03, 2025 pm 02:57 PM

多線程和異步的區別在於,多線程同時執行多個線程,而異步在不阻塞當前線程的情況下執行操作。多線程用於計算密集型任務,而異步用於用戶交互操作。多線程的優勢是提高計算性能,異步的優勢是不阻塞 UI 線程。選擇多線程還是異步取決於任務性質:計算密集型任務使用多線程,與外部資源交互且需要保持 UI 響應的任務使用異步。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在這裡,我們討論 C# 中模式的介紹和前 3 種類型,以及其範例和程式碼實作。

C# 中的質數 C# 中的質數 Sep 03, 2024 pm 03:35 PM

C# 質數指南。這裡我們討論c#中素數的介紹和範例以及程式碼實作。

手機上如何將XML轉換成PDF? 手機上如何將XML轉換成PDF? Apr 02, 2025 pm 10:18 PM

直接在手機上將XML轉換為PDF並不容易,但可以藉助雲端服務實現。推薦使用輕量級手機App上傳XML文件並接收生成的PDF,配合雲端API進行轉換。雲端API使用無服務器計算服務,選擇合適的平台至關重要。處理XML解析和PDF生成時需要考慮複雜性、錯誤處理、安全性和優化策略。整個過程需要前端App與後端API協同工作,需要對多種技術有所了解。

See all articles