# [C# 網絡編程系列]專題五:TCP編程
**前言**
前面專題的例子都是基于應用層上的HTTP協議的介紹, 現在本專題來介紹下傳輸層協議——TCP協議,主要介紹下TCP協議的工作過程和基于TCP協議的一個簡單的通信程序,下面就開始本專題的正文了。
**一、TCP的工作過程**
首先TCP是一種面向連接的,可靠的,基于字節流的傳輸層通信協議。TCP的工作過程可以分為三個階段:一、連接的建立; 二、傳輸數據; 三、斷開連接,下面就對這三個過程分別介紹下:
**1.1 連接的建立**
TCP的連接建立就像打電話一樣, 我們打電話時,撥一個號碼的號碼并不是立即就可以接通的,期間會有一個“嘟 嘟”的呼叫過程, 這就好比是TCP協議的連接的建立階段。當我們用TCP編寫的程序,必須先建立TCP連接。TCP協議的連接建立通過三次握手來完成的,下面是在網上找的一張TCP三次握手的圖片:

下面就對這三次握手簡單的介紹:
第一次握手:建立連接時,客戶端發送SYN包(seq=x)到服務器,并進入SYN_Send狀態,等待服務器確認
第二次握手:服務器收到SYN包,必須確認客戶的SYN(ACK=x+1),同時自己也發送一個SYN包(SEQ=y),即SYN+ACK包,此時服務器進入SYN_Recv狀態
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ACK=y+1),此包發送完畢,客戶端和服務器進入Established(建立)狀態,完成三次握手。
簡單理解三次握手就是發送一個檢驗包給對方然后互相確認,雙方都接到確認的一個信號時,這時候雙方就建立了連接(就像我們打電話時,如果沒人說話時就會說下 “喂”,說這句“喂” 也就是希望得到對方的一個確認,雖然這里雙方已經建立了連接的,這里只是更形象的說明下三次握手的過程)。
**1.2 傳輸數據**
雙方建立了連接,即在雙方建立了一個通信通道(就像一座橋一樣,在兩端建立了一個通路,用橋來比喻通信通道主要是因為最近有一則新聞:哈爾濱陽明灘大橋坍塌事件),建立連接之后,當然是傳輸我們需要傳輸的數據到對方的,這里就開始簡單介紹下傳輸數據的過程。
利用TCP傳輸數據時,數據是以字節流的形式進行傳輸,客戶端與服務器端建立連接后,發送方需要先將發送的數據轉換為字節流,然后將其發送給對方,發送數據時,可以通過程序不斷地將數據流陸續寫入TCP的發送緩沖中,然后TCP自動從發送緩沖中提取一定量的數據,將其組成TCP報文段發送到IP層,再通過IP層(也就是網絡層)之下的網絡接口發送出去;接受端從IP層接收到TCP報文段后,將其暫時保存在接受緩沖中,然后我們通過程序依次讀取接受緩沖中的數據,從而達到相互通信的目的(簡單的說就發送方把數據轉換為數據流,再把數據流存儲在發送緩沖中,然后傳輸層低層的協議從發送緩沖中讀取數據把數據發送出去,然后接收端從底層接受到數據把數據存儲在接收端的緩沖中,然后我們寫的程序只是從緩沖中依次讀取數據,然后顯示出來,在客戶端我們寫代碼做的事情是把數據寫入Write寫入發送端的緩沖中,然后服務器端(接收端)用Read方法在自己的緩沖中讀取數據,用一句話概括,TCP的傳輸就是對數據的寫——讀操作)括號中的內容只是我個人理解,因為這樣我感覺理解起來比較容易,對于剛開始接觸TCP的朋友可以這樣理解,然后再一句句話去擴展。
**1.3 斷開連接**
發送完數據之后,最后就是斷開連接了,下面是網上斷開的連接的一張圖片(斷開一個連接需要經過四次握手):

TCP的工作過程就分為上面三個過程,TCP編程是作為上層應用編程的基礎,就像之前專題中基于HTTP協議的Web服務器,Web瀏覽器,其傳輸層都用的是TCP協議進行傳輸的,還有基于FTP(文件傳輸協議),IMAP(交互式郵件存取協議) POP3(郵局協議的第3個版本) 和SMTP(簡單郵件傳輸協議)的網絡應用其傳輸層都用的是TCP協議,而不是UDP等其他傳輸層協議。
**二、基于TCP協議的簡單通信程序**
這里簡單實現了一個客戶端與服務器間的通信程序,核心代碼為:
客戶端連接服務器端代碼:
```
private void btnConnect_Click(object sender, EventArgs e)
{
// 通過一個線程發起請求,多線程
Thread connectThread = new Thread(ConnectToServer);
connectThread.Start();
}
// 連接服務器方法,建立連接的過程
private void ConnectToServer()
{
try
{
// 調用委托
statusStripInfo.Invoke(showStatusCallBack, "正在連接...");
if (tbxserverIp.Text == string.Empty || tbxPort.Text == string.Empty)
{
MessageBox.Show("請先輸入服務器的IP地址和端口號");
}
IPAddress ipaddress = IPAddress.Parse(tbxserverIp.Text);
tcpClient = new TcpClient();
tcpClient.Connect(ipaddress, int.Parse(tbxPort.Text));
// 延時操作
Thread.Sleep(1000);
if (tcpClient != null)
{
statusStripInfo.Invoke(showStatusCallBack, "連接成功");
networkStream = tcpClient.GetStream();
reader = new BinaryReader(networkStream);
writer =new BinaryWriter(networkStream);
}
}
catch
{
statusStripInfo.Invoke(showStatusCallBack,"連接失敗");
Thread.Sleep(1000);
statusStripInfo.Invoke(showStatusCallBack,"就緒");
}
}
```
客戶端發送消息的代碼:
```
// 發送消息
private void btnSend_Click(object sender, EventArgs e)
{
Thread sendThread = new Thread(SendMessage);
sendThread.Start(tbxMessage.Text);
}
private void SendMessage(object state)
{
statusStripInfo.Invoke(showStatusCallBack, "正在發送...");
try
{
writer.Write(state.ToString());
Thread.Sleep(5000);
writer.Flush();
statusStripInfo.Invoke(showStatusCallBack, "完畢");
tbxMessage.Invoke(resetMessageCallBack, null);
lstbxMessageView.Invoke(showMessageCallback, state.ToString());
}
catch
{
if (reader != null)
{
reader.Close();
}
if (writer != null)
{
writer.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
statusStripInfo.Invoke(showStatusCallBack, "斷開了連接");
}
}
```
服務器端接受開始監聽客戶端請求的代碼:
```
// 開始監聽
private void btnStart_Click(object sender, EventArgs e)
{
tcpLister = new TcpListener(ipaddress,Port);
tcpLister.Start();
// 啟動一個線程來接受請求
Thread acceptThread =new Thread(acceptClientConnect);
acceptThread.Start();
}
// 接受請求
private void acceptClientConnect()
{
statusStripInfo.Invoke(showStatusCallBack,"正在監聽");
Thread.Sleep(1000);
try
{
statusStripInfo.Invoke(showStatusCallBack,"等待連接");
tcpClient = tcpLister.AcceptTcpClient();
if (tcpLister != null)
{
statusStripInfo.Invoke(showStatusCallBack,"接受到連接");
networkStream = tcpClient.GetStream();
reader = new BinaryReader(networkStream);
writer = new BinaryWriter(networkStream);
}
}
catch
{
statusStripInfo.Invoke(showStatusCallBack, "停止監聽");
Thread.Sleep(1000);
statusStripInfo.Invoke(showStatusCallBack, "就緒");
}
}
```
現在看看運行的結果: 首先先啟動服務器然后點開始監聽,此時線程會堵塞,直到接受到一個連接請求位置

然后運行客戶端,在IP地址和端口處輸入服務器端的IP地址和端口號,點擊連接服務器按鈕后的界面如下:

通過接受按鈕和發送按鈕來實現雙方的通信,實現界面如下:

**三、總結**
到這里本專題的內容將的差不多了, 本專題主要介紹了基于TCP協議工作過程和在net平臺下自定義了一個簡單通信的程序,希望本專題可以給那些初次接觸TCP協議的朋友一些幫助,(大牛們應該直接可以閃過的),在后面的專題我將和大家分享UDP編程,講完UDP編程后將結合這兩章的內容實現一個類似QQ的即時聊天的工具,希望這些對大家有幫助,如果大家有任何問題和有感興趣的專題需要了解的,可以給我留言,在之后的文章都會和大家來分享。
覺得看了后有幫助的朋友麻煩推薦下,也給我繼續下去的動力,如果大家有什么感興趣的專題也可以留言告訴我,我會通過學習后也會相繼和大家分享。
下面是本程序源代碼:
[http://files.cnblogs.com/zhili/%E7%AE%80%E5%8D%95%E9%80%9A%E4%BF%A1%E7%A8%8B%E5%BA%8F.zip](http://files.cnblogs.com/zhili/%E7%AE%80%E5%8D%95%E9%80%9A%E4%BF%A1%E7%A8%8B%E5%BA%8F.zip)
- C# 基礎知識系列
- C# 基礎知識系列 專題一:深入解析委托——C#中為什么要引入委托
- C# 基礎知識系列 專題二:委托的本質論
- C# 基礎知識系列 專題三:如何用委托包裝多個方法——委托鏈
- C# 基礎知識系列 專題四:事件揭秘
- C# 基礎知識系列 專題五:當點擊按鈕時觸發Click事件背后發生的事情
- C# 基礎知識系列 專題六:泛型基礎篇——為什么引入泛型
- C# 基礎知識系列 專題七: 泛型深入理解(一)
- C# 基礎知識系列 專題八: 深入理解泛型(二)
- C# 基礎知識系列 專題九: 深入理解泛型可變性
- C#基礎知識系列 專題十:全面解析可空類型
- C# 基礎知識系列 專題十一:匿名方法解析
- C#基礎知識系列 專題十二:迭代器
- C#基礎知識 專題十三:全面解析對象集合初始化器、匿名類型和隱式類型
- C# 基礎知識系列 專題十四:深入理解Lambda表達式
- C# 基礎知識系列 專題十五:全面解析擴展方法
- C# 基礎知識系列 專題十六:Linq介紹
- C#基礎知識系列 專題十七:深入理解動態類型
- 你必須知道的異步編程 C# 5.0 新特性——Async和Await使異步編程更簡單
- 全面解析C#中參數傳遞
- C#基礎知識系列 全面解析C#中靜態與非靜態
- C# 基礎知識系列 C#中易混淆的知識點
- C#進階系列
- C#進階系列 專題一:深入解析深拷貝和淺拷貝
- C#進階系列 專題二:你知道Dictionary查找速度為什么快嗎?
- C# 開發技巧系列
- C# 開發技巧系列 使用C#操作Word和Excel程序
- C# 開發技巧系列 使用C#操作幻燈片
- C# 開發技巧系列 如何動態設置屏幕分辨率
- C# 開發技巧系列 C#如何實現圖片查看器
- C# 開發技巧 如何防止程序多次運行
- C# 開發技巧 實現屬于自己的截圖工具
- C# 開發技巧 如何使不符合要求的元素等于離它最近的一個元素
- C# 線程處理系列
- C# 線程處理系列 專題一:線程基礎
- C# 線程處理系列 專題二:線程池中的工作者線程
- C# 線程處理系列 專題三:線程池中的I/O線程
- C# 線程處理系列 專題四:線程同步
- C# 線程處理系列 專題五:線程同步——事件構造
- C# 線程處理系列 專題六:線程同步——信號量和互斥體
- C# 多線程處理系列專題七——對多線程的補充
- C#網絡編程系列
- C# 網絡編程系列 專題一:網絡協議簡介
- C# 網絡編程系列 專題二:HTTP協議詳解
- C# 網絡編程系列 專題三:自定義Web服務器
- C# 網絡編程系列 專題四:自定義Web瀏覽器
- C# 網絡編程系列 專題五:TCP編程
- C# 網絡編程系列 專題六:UDP編程
- C# 網絡編程系列 專題七:UDP編程補充——UDP廣播程序的實現
- C# 網絡編程系列 專題八:P2P編程
- C# 網絡編程系列 專題九:實現類似QQ的即時通信程序
- C# 網絡編程系列 專題十:實現簡單的郵件收發器
- C# 網絡編程系列 專題十一:實現一個基于FTP協議的程序——文件上傳下載器
- C# 網絡編程系列 專題十二:實現一個簡單的FTP服務器
- C# 互操作性入門系列
- C# 互操作性入門系列(一):C#中互操作性介紹
- C# 互操作性入門系列(二):使用平臺調用調用Win32 函數
- C# 互操作性入門系列(三):平臺調用中的數據封送處理
- C# 互操作性入門系列(四):在C# 中調用COM組件
- CLR
- 談談: String 和StringBuilder區別和選擇
- 談談:程序集加載和反射
- 利用反射獲得委托和事件以及創建委托實例和添加事件處理程序
- 談談:.Net中的序列化和反序列化
- C#設計模式
- UML類圖符號 各種關系說明以及舉例
- C#設計模式(1)——單例模式
- C#設計模式(2)——簡單工廠模式
- C#設計模式(3)——工廠方法模式
- C#設計模式(4)——抽象工廠模式
- C#設計模式(5)——建造者模式(Builder Pattern)
- C#設計模式(6)——原型模式(Prototype Pattern)
- C#設計模式(7)——適配器模式(Adapter Pattern)
- C#設計模式(8)——橋接模式(Bridge Pattern)
- C#設計模式(9)——裝飾者模式(Decorator Pattern)
- C#設計模式(10)——組合模式(Composite Pattern)
- C#設計模式(11)——外觀模式(Facade Pattern)
- C#設計模式(12)——享元模式(Flyweight Pattern)
- C#設計模式(13)——代理模式(Proxy Pattern)
- C#設計模式(14)——模板方法模式(Template Method)
- C#設計模式(15)——命令模式(Command Pattern)
- C#設計模式(16)——迭代器模式(Iterator Pattern)
- C#設計模式(17)——觀察者模式(Observer Pattern)
- C#設計模式(18)——中介者模式(Mediator Pattern)
- C#設計模式(19)——狀態者模式(State Pattern)
- C#設計模式(20)——策略者模式(Stragety Pattern)
- C#設計模式(21)——責任鏈模式
- C#設計模式(22)——訪問者模式(Vistor Pattern)
- C#設計模式(23)——備忘錄模式(Memento Pattern)
- C#設計模式總結
- WPF快速入門系列
- WPF快速入門系列(1)——WPF布局概覽
- WPF快速入門系列(2)——深入解析依賴屬性
- WPF快速入門系列(3)——深入解析WPF事件機制
- WPF快速入門系列(4)——深入解析WPF綁定
- WPF快速入門系列(5)——深入解析WPF命令
- WPF快速入門系列(6)——WPF資源和樣式
- WPF快速入門系列(7)——深入解析WPF模板
- WPF快速入門系列(8)——MVVM快速入門
- WPF快速入門系列(9)——WPF任務管理工具實現
- ASP.NET 開發
- ASP.NET 開發必備知識點(1):如何讓Asp.net網站運行在自定義的Web服務器上
- ASP.NET 開發必備知識點(2):那些年追過的ASP.NET權限管理
- ASP.NET中實現回調
- 跟我一起學WCF
- 跟我一起學WCF(1)——MSMQ消息隊列
- 跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(4)——第一個WCF程序
- 跟我一起學WCF(5)——深入解析服務契約 上篇
- 跟我一起學WCF(6)——深入解析服務契約 下篇
- 跟我一起學WCF(7)——WCF數據契約與序列化詳解
- 跟我一起學WCF(8)——WCF中Session、實例管理詳解
- 跟我一起學WCF(9)——WCF回調操作的實現
- 跟我一起學WCF(10)——WCF中事務處理
- 跟我一起學WCF(11)——WCF中隊列服務詳解
- 跟我一起學WCF(12)——WCF中Rest服務入門
- 跟我一起學WCF(13)——WCF系列總結
- .NET領域驅動設計實戰系列
- .NET領域驅動設計實戰系列 專題一:前期準備之EF CodeFirst
- .NET領域驅動設計實戰系列 專題二:結合領域驅動設計的面向服務架構來搭建網上書店
- .NET領域驅動設計實戰系列 專題三:前期準備之規約模式(Specification Pattern)
- .NET領域驅動設計實戰系列 專題四:前期準備之工作單元模式(Unit Of Work)
- .NET領域驅動設計實戰系列 專題五:網上書店規約模式、工作單元模式的引入以及購物車的實現
- .NET領域驅動設計實戰系列 專題六:DDD實踐案例:網上書店訂單功能的實現
- .NET領域驅動設計實戰系列 專題七:DDD實踐案例:引入事件驅動與中間件機制來實現后臺管理功能
- .NET領域驅動設計實戰系列 專題八:DDD案例:網上書店分布式消息隊列和分布式緩存的實現
- .NET領域驅動設計實戰系列 專題九:DDD案例:網上書店AOP和站點地圖的實現
- .NET領域驅動設計實戰系列 專題十:DDD擴展內容:全面剖析CQRS模式實現
- .NET領域驅動設計實戰系列 專題十一:.NET 領域驅動設計實戰系列總結