[精讚] [會員登入]
12668

[C#] 撰寫非同步方法 TCP socket #1

非同步的TCP連線程式才是撰寫連線程式的唯一道路,此文僅供參考

分享此文連結 //n.sfs.tw/11625

分享連結 [C#] 撰寫非同步方法 TCP socket #1@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2019-10-25 14:13:39 最後編修
2017-08-14 21:15:21 By 張○○
 

自動目錄

此文分為二個部分

[C#] 撰寫非同步方法 TCP socket #1

[C#] 撰寫非同步方法 TCP socket #2

一、前言

在TCP連線中,如果是同步狀態,當SERVER LISTEN 一個埠時,整個程式就會停駐在此,等候用戶傳送資料進來,如果沒資料傳送,整個程式就好像是當掉一樣。當此時別的客戶想連線時,因為插座被佔了,除非 fork另一個程序(或是另開一個應用層的THREAD,否則別想連線,所以一般伺服器的SOCKET 都會以非同步的方法撰寫。

TCP連線主要有分為同步/非同步兩種方法(Synchronous/Asynchronous Methods) [1][2];在同步方法中,程式一次只能進行一個要求(request),並且會延遲其他的要求。例如當程式在等候資料傳送進來(Waiting),執行同步要求的執行緒因等候網路作業完成而無法再執行其他工作,包括使用者介面(UI)執行緒,那麼應用程式就會暫停並停止回應使用者的輸入。

此外,當此時別的客戶端想連線時,因為唯一的一個 Socket已被佔用,無法再接受其他的客戶連線。雖然使用同步的方法從觀念上來說比較容易使用,然而如果應用程式需要保持快速回應、提升延展性及可靠性及達到同時連線的目的,那麼就不應該使用同步封鎖的作業方式。

非同步方法的連線中,程式不會因為等候同步作業完成的執行緒而被封鎖。因為非同步作業(Asynchronous Operation)會在不同的執行緒上(在背景中)執行,所以應用程式可以在呼叫非同步方法(BeginOperationName)的執行緒上繼續執行。這樣的好處是有效率、高雅(不會因等待而暫停)並且能同時和許多個Clients建立連線,缺點是程式碼較不易撰寫。

在C#中,同步及非同步的連線的方法差異如下:

Synchronous Methods Asynchronous Methods
Connect()
建立至遠端主機的連接

BeginConnect()
開始遠端主機連接的非同步要求

EndConnect()
結束擱置的非同步連接要求

Receive()
從已繫結的 Socket 接收資料
 

BeginReceive()
啟始非同步接收作業,方法是告知訊息佇列開始接收訊息,並在完成時告知事件處理常式。

EndReceive()
完成指定的非同步接收作業。

相對的,非同步的連線中,當Server已接受一個Clent的連線時,同時也能接收其他的Clients連線的請求。當其中一個Client傳送資料 時, 該插座Socket會啟動一個回呼CallBack事件,這個回呼事件會執行你所指定的函式(function),這在C#中叫作delegate,也就 是C++中的指標,而不同的是,在C#中是稱為「物件導向函式指標」,他指向一個函式,本文會對這方面作很多的說明,因為瞭解它是進入中高階程設的里程埤。

二、伺服器端程式

using System.Net;

// 宣告Socket 類 mainSocket 為 class 變數
private Socket mainSocket;
int port=12345;

// 伺服函式
public function Server()
{
  // 實體化 mainSocket
  mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

  //建立本機監聽位址及埠號,IPAddress.Any表示監聽所有的介面。
  IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);

  //socket連繫到該位址
  mainSocket.Bind(ipLocal);

 // 啟動監聽
 //backlog=4 參數會指定可在佇列中等候接收的輸入連接數。若要決定可指定的最大連接數,
   除非同時間的連線非常的大,否則值4應該很夠用。
 mainSocket.Listen(4);

 // 以上完成了SERVER的Listening,BeginAccept() 開啟執行緒準備接收client的要求。
 // 此處的BeginAccept 第一個參數就是當Socket一開始接收到Client的連線要求時,
    立刻會呼叫delegate的OnClientConnect的方法,這個OnClientConnect名稱是我們自己取的,
    你也可以叫用別的名稱。因此我們要另外寫一個OnClientConnect()的函式。
  mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}

[灰色字是原理說明]

這裡我們先來看BeginAccept的說明:開始非同步作業以接受連入的連接嘗試。
public IAsyncResult BeginAccept (
    AsyncCallback callback,
    Object state
)

就 AsyncCallback 類別而言,他是一個代理人的函數。注意看到的delegate的型別,用淺紅色顯示:
public delegate void AsyncCallback (
     IAsyncResult ar
)

值得注意的,在此AsyncCallback類別中,有一個參數是IAsyncResult ar表示非同步作業(Asynchronous Operation) 的狀態:public interface IAsyncResult
換句話說,在實作OnClientConnect 函數時,他必需引用一個IAsyncResult的參數。這裡的 IAsyncResult 本身是一個介面,即只有定義沒有實作項的類別,他有幾個屬性,我們以後會用到:

  • AsyncState 取得符合或包含非同步作業資訊的使用者定義的物件。
  • AsyncWaitHandle 取得 WaitHandle,用於等候非同步作業完成。
  • CompletedSynchronously 取得非同步作業是否同步完成的指示。
  • IsCompleted 取得非同步作業是否已完成的指示。

介面不是本文的重點,所以就先略過。接下來實作 CallBack 的函式。

要觸發 Server() 函式,可以拉一個按鈕,onclick  事件時呼叫他,或是在初始化時呼叫亦可,總之,Server() 執行後,伺服端程式已啟動監聽的工作。

更難的在這裡 [C#] 撰寫非同步方法 TCP socket #2

參考書目

[1] Beej's Guide to Network Programming Using Internet Sockets, Brian 「Beej」 Hall beej@beej.us Version 2.3.23, November 5, 2005

[2] David Makofske, Michael J. Donahoo, Kenneth L. Calvert TCP/IP Sockets in C#: Practical Guide for Programmers, The Practical Guides, Morgan Kaufmann 2004 .


原文 2010-04-02 00:52:54 撰於 97.7~8 間,從論文的一部分整理出來發佈給需要的人參考

END

你可能感興趣的文章

[C#] 從MySql資料庫取得的中文字是亂碼的處理 從MySql資料庫取得的中文字是亂碼

[C#] 撰寫非同步方法 TCP socket #2 非同步的TCP連線程式才是撰寫連線程式的唯一道路,此文僅供參考

[C#] 撰寫非同步方法 TCP socket #1 非同步的TCP連線程式才是撰寫連線程式的唯一道路,此文僅供參考

C# 取得滑鼠位置 C# Application中取得滑鼠位置

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

為什麼要買長達二十年的保單? 為什麼要買長達二十年的保單?找一個可以說服我買二十年保單的理由。

如何在linux下執行java 原生的java應用程式可以使用簡單的方法在console下面寫出來,適合作簡單的應用

PHP for sphinx 函式庫安裝 PECL/sphinx PHP>= 5.2.2 已經能原生支援 sphinx,可是預設的沒有裝,我們得自己裝才能用

UTF-8的網頁但IE8一片空白 UTF8編碼的網頁在Firefox 正常顯示、但IE8 就是空白,IE8編碼設定是「自動偵測」可是自動偵測到的是 big5...

對物品的感情 這個議題很奇怪,可是大部分的人都會有,物品是死的,壞了就淘汰,出新的就被替換。為何會有情感?