TCP 協議(Transmission Control Protocol,傳輸控制通訊協定)是TCP/IP體系中連線導向(connection oriented)的傳輸層(transport layer),TCP協議能夠檢測和恢複IP層提供的主機到主機的通道中可能發生的報文丟失、重複以及其他錯誤。由於TCP協議是一種連線導向協議:在使用它進行通訊之前,兩個應用程式之間首先要建立一個TCP串連。TCP能夠在網路中提供雙工和可靠的的服務。
閱讀目錄:
1.TCP概述
2.在.NET平台TCP應用的工作模式
2.1 瞭解TcpListener和TcpClient
3.解決TCP的訊息無邊界問題
3.1 發送固定長度的訊息
3.2 將訊息長度與訊息一起發送
3.3 使用特殊標記分隔訊息
4.一個同步TCP Socket樣本
5.樣本源碼下載
6.進一步閱讀&參考資料
1.TCP概述
通訊雙方建立了TCP串連後,雙方就可以相互發送資料了。TCP負責把使用者資料(位元組流)按照一定格式和長度組成多個資料報進行發送,然後在接到資料報之後分解按順序重新組裝和恢複使用者資料。利用TCP傳輸資料時,資料時以位元組的形式進行傳輸的。用戶端和服務端建立串連後,發送資料方需要先將資料轉換為位元組流,然後將位元組流發送到對方。TCP協議主要有以下特點:
- 是連線導向的傳輸層協議
- 每個TCP串連只能有兩個端點,且只能一對一通訊
- 通過TCP串連傳送資料能夠保證報文的完整和準確性
- 資料只能夠以位元組流的形式傳輸
- 傳輸的資料無訊息邊界
2.在.NET平台TCP應用的工作模式
在.NET平台下開發TCP應用程式,架構提供兩種工作方式,①同步工作方式 ②非同步工作方式。這裡所說的同步工作方式和非同步工作方式和線程間的同步並不是一個概念。線程間的同步指的是不同線程或其他共用資源具有先後關聯的關係;而同步TCP和非同步TCP指的是TCP編程中採用的兩種不同的工作方式,即:從執行到方式、接收或監聽語句時,程式是否繼續往下執行,繼續執行的就是非同步TCP,如果程式阻塞那就是同步TCP。
與同步工作方式和非同步工作方式相對應,利用Socket類開發應用.NET架構也提供了相應的編程方式:分別是同步Socket編程和非同步Socket編程。為了簡化編程的複雜度,.NET將Socket類進行進一步的封裝,提供了兩個類:TcpClient類和TcpListener類,這兩個類也分別提供同步和非同步工作方式的API。
2.1 瞭解TcpListener和TcpClient
通過前面我們知道:TcpClient類和TcpListener類簡化了Socket編程的複雜度,但是要注意:TcpClient和TcpListener這兩個類只支援標準協議編程,如果需要編寫非標準協議的應用程式,只能使用Socket來實現。
TcpClient類用於提供本機主機和遠程主機的串連資訊,而TcpListener類則用於監聽用戶端的請求(這兩個類的更多資訊可以參考MSDN類庫,文中已經給出串連,這裡就不在贅述了)。當Socket通訊雙發建立了串連後,建立了TcpClient對象,就可以使用該對象的GetStream()方法得到NetworkStream對象,然後再利用網路流對象向遠程主機發送或接收流資料。
3.解決TCP的無訊息邊界問題
我們知道網路資料轉送是基於流的,在採用TCP通訊保證了我們接收和發送資料順序和完整性,但是在實際的網路傳輸過程可能會出現發送方和接收方訊息不一致的情況。例如:第一次發送的資料為“123456”,第二次發送的資料為“ABCDEF”,有時候可能會出現這種情況:“123456ABCDEF”同時接收了;或者是先接收“123456ABC”,然後在接收“DEF”等情況。之所以出現這種情況是因為:TCP是一種以位元組流形式傳輸的、無訊息邊界的協議,由於網路中不確定因數的影響,因此不能夠保證每個Send方法發送的資料被對應的Recive讀取。所以在實際的Socket應用程式開發是必須要考慮訊息邊界的問題否則就有可能出現資料錯誤等問題。解決TCP訊息邊界一般使用下面的三種方式,我們可以根據情境的不同選用不同的方式。
3.1 發送固定長度的訊息
這種方式適用於訊息長度固定的情境。具體實現時可以使用BinaryReader/BinaryWriter對象每次向網路流,發送/讀取一個固定長度的資料即可。例如每次發送一個int類型的32位整數。
1 TcpClient client = new TcpClient("www.baidu.com", 5968);2 NetworkStream m_NetStream = client.GetStream();3 BinaryWriter bw = new BinaryWriter(m_NetStream, Encoding.UTF8);4 bw.Write(99);
3.2 將訊息長度與訊息一起發送
這種方式一般在每次發送訊息的前面用4個位元組表面本次訊息的長度,然後將包含訊息長度的訊息發送給對方;對方收到訊息後,首先從訊息的前四個位元組讀取訊息長度,然後根據訊息長度值接收發送方發送的資料。這種方法適用於任何場合,在這裡我們可以利用BinaryReader和BinaryWriter對象來對NetworkStream進行進一步的封裝,當我們使用BinaryWriter對象調用Write(+18重載)方法向網路流寫入資料時,該方法會自動計算髮出送資料佔用的位元組數,並使用4(根據發送資料類型)個位元組附加到字串前面;然後另一方使用BinaryReader對象的對應於BinaryWriter對象的Write()方法讀取資料時,它會首先讀取資料的長度,並自動根據資料首碼讀取指定長度的資料。
3.3 使用特殊標記分隔訊息
這種方式適用於訊息中不包含特殊標記的場合。例如:在每個命令後面添加斷行符號換行(\r\n)符號作為分隔字元的場合。如果對於字串處理,實現這種方法最簡便的途徑是使用StreamWriter對象和StreamReader對象。發送時使用StreamWriter對象的WriteLine()方法將發送的字串寫入網路流,接收方只需需要調用StreamReader對象的ReadLine()方法將以斷行符號分行符號作為分隔字元的字串從網路流中讀取即可。
4.同步TCP Socket 樣本程式
經過前面知識的積澱,現在我們直接通過建立一個簡單的聊天程式來基於同步TCP Socket網路聊天程式,程式的實現比較簡單,伺服器接收多個用戶端串連,用戶端和用戶端直接通過伺服器代理訊息達到相互連信的目的。用戶端和伺服器直接的訊息互動使用JSON來進行傳遞,在這裡使用了第三方的JSON庫JSON.NET(關於JSON.NET的使用細節參考:JSON.NET使用小結)。下面是程式啟動並執行效果:
運行服務端:
開啟多個用戶端,在線上列表中選擇聊天對象,發送聊天資訊:
樣本源碼:猛擊下載
參考資料&進一步閱讀
維基百科:傳輸控制通訊協定(TCP)
《C#網路應用編程2》
作者:晴天豬
出處:http://www.cnblogs.com/IPrograming
本文著作權歸作者和部落格園共有,歡迎轉載,並請註明出處。