TCP是Transmission Control Protocol(傳輸控制協(xié)議)的簡(jiǎn)稱涨醋,是TCP/IP體系中面向連接的運(yùn)輸層協(xié)議,在網(wǎng)絡(luò)中提供全雙工的和可靠的服務(wù)癌蚁。
TCP最主要的特點(diǎn):
(1)是面向連接的傳輸層協(xié)議;
(2)每個(gè)TCP連接只能有兩個(gè)端點(diǎn)匾竿,而且只能一對(duì)一通信,不能一點(diǎn)對(duì)多點(diǎn)直接通信。
(3)通過(guò)TCP連接傳送的數(shù)據(jù)辫诅,能保證數(shù)據(jù)無(wú)差錯(cuò)、不丟失涧狮、不重復(fù)地準(zhǔn)確到達(dá)接收方炕矮,并且保證各數(shù)據(jù)到達(dá)的順序與數(shù)據(jù)發(fā)出的順序相同。
(4)數(shù)據(jù)以字節(jié)流的方式傳輸者冤。
(5)傳輸?shù)臄?shù)據(jù)無(wú)消息邊界肤视。
利用TCP開(kāi)發(fā)應(yīng)用程序時(shí),.NET框架提供兩種工作方式.
(1)同步工作方式
指利用TCP編寫的程序執(zhí)行到發(fā)送涉枫、接收或監(jiān)聽(tīng)語(yǔ)句時(shí)邢滑,在未完成工作前不再繼續(xù)往下執(zhí)行,即處于阻塞狀態(tài)愿汰,直到該語(yǔ)句完成相應(yīng)的工作后才繼續(xù)執(zhí)行下一條語(yǔ)句困后;
(2)異步工作方式
異步工作方式是指程序執(zhí)行到發(fā)送、接收或監(jiān)聽(tīng)語(yǔ)句時(shí)衬廷,不論工作是否完成摇予,都會(huì)繼續(xù)往下執(zhí)行。
例如:同步接收數(shù)據(jù)時(shí)泵督,接收方執(zhí)行到接收語(yǔ)句后將處于阻塞方式趾盐,只有接收到對(duì)方發(fā)來(lái)的數(shù)據(jù)后才繼續(xù)執(zhí)行下一條語(yǔ)句;而如果采用異步工作方式小腊,則接收方在執(zhí)行到接收語(yǔ)句后救鲤,無(wú)論是否接收到對(duì)方發(fā)來(lái)的數(shù)據(jù),程序都繼續(xù)往下執(zhí)行秩冈。
思考:這里的同步TCP和異步TCP與線程同步異步是否概念是否相同本缠?
回答:
(1)這里的同步TCP和異步TCP僅僅指工作方式,它和線程間的同步不是一個(gè)概念入问。
(2)線程間的同步指不同線程或其共享資源具有先后關(guān)聯(lián)的關(guān)系丹锹,而同步TCP和異步TCP則僅僅指TCP編程中采用哪種工作方式,即是從執(zhí)行到發(fā)送芬失、接收或監(jiān)聽(tīng)語(yǔ)句時(shí)楣黍,程序是否繼續(xù)往下執(zhí)行這個(gè)角度來(lái)說(shuō)的。
TcpListener類與TcpClient類
TcpListener類與TcpClient類兩個(gè)類均封裝了底層的套接字棱烂,并分別提供了對(duì)套接字進(jìn)一步封裝后的同步和異步操作的方法租漂,降低了TCP應(yīng)用編程的難度。
TcpListener類用于偵聽(tīng)和接受傳入的連接請(qǐng)求。
TcpClient類用于提供本地主機(jī)和遠(yuǎn)程主機(jī)的連接信息哩治。
注意秃踩,TcpListener和TcpClient只支持標(biāo)準(zhǔn)協(xié)議編程。如果希望編寫非標(biāo)準(zhǔn)協(xié)議的程序业筏,只能使用套接字來(lái)實(shí)現(xiàn)憔杨。
TcpListener類
TcpLISTener類在System.Net.Socket命名空間下。
常用的構(gòu)造函數(shù)有兩種:TcpListener(IPEndPoint iep)
TcpListener(IPAddress localAddr, int port)
舉例:
IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
Try
{
TcpListener tcpListener = new TcpListener(ipAddress, 1326);
}
catch ( Exception e)
{
Console.WriteLine( e.ToString());
}
在同步工作方式下蒜胖, TcpListener類常用的方法:
Start啟動(dòng)監(jiān)聽(tīng)消别,構(gòu)造函數(shù)為:public void Start([int backlog])參數(shù)backlog為請(qǐng)求隊(duì)列的最大長(zhǎng)度,即最多允許的的客戶端請(qǐng)求連接個(gè)數(shù)台谢;
Stop關(guān)閉TcpListener并停止監(jiān)聽(tīng)請(qǐng)求妖啥,構(gòu)造函數(shù)為:public void Stop();
AcceptSocket
在同步阻塞方式下獲取并返回一個(gè)用來(lái)接收和發(fā)送數(shù)據(jù)的Socket對(duì)象,同時(shí)從傳入的連接隊(duì)列中移除該客戶端的連接請(qǐng)求对碌。
AcceptTcpClient在同步阻塞方式下獲取并返回一個(gè)封裝了Socket的TcpClient對(duì)象荆虱,同時(shí)從傳入的連接隊(duì)列中移除該客戶端的連接請(qǐng)求。
TcpClient類
TcpClient類在System.Net.Socket命名空間下朽们。
主要用于編寫客戶端程序怀读,且需要直接利用構(gòu)造函數(shù)創(chuàng)建TcpClient對(duì)象。而服務(wù)器端程序中是通過(guò)TcpListener對(duì)象的AcceptTcpClient方法得到TcpClient對(duì)象的骑脱,所以不需要使用TcpClient類的構(gòu)造函數(shù)來(lái)創(chuàng)建TcpClient對(duì)象菜枷。
構(gòu)造函數(shù)有四種重載形式
- TcpClient()
- TcpClient(AddressFamily family)
- TcpClient(IPEndPoint iep)
- TcpClient(string hostname,int port)
(1)TcpClient()
該構(gòu)造函數(shù)創(chuàng)建一個(gè)默認(rèn)的TcpClient對(duì)象叁丧,并自動(dòng)分配本機(jī)(客戶端)IP地址和端口號(hào)啤誊。利用此構(gòu)造函數(shù)創(chuàng)建對(duì)象后,還必須調(diào)用Connect方法與服務(wù)器建立連接拥娄。
例如:
TcpClient tcpClient=new TcpClient();
tcpClient.Connect("www.abcd.com", 51888);
(2)TcpClient(AddressFamily family)
該構(gòu)造函數(shù)創(chuàng)建的TcpClient對(duì)象也能自動(dòng)分配本機(jī)(客戶端)IP地址和端口號(hào)蚊锹,但是使用AddressFamily枚舉指定使用哪種網(wǎng)絡(luò)協(xié)議。創(chuàng)建該對(duì)象后稚瘾,必須調(diào)用Connect方法與服務(wù)器建立連接牡昆。
例如:
TcpClient tcpClient = new TcpClient(AddressFamily.InterNetwork);
tcpClient.Connect("www.abcd.com", 51888);
(3)TcpClient(IPEndPoint iep)
該構(gòu)造函數(shù)的參數(shù)iep指定本機(jī)(客戶端)IP地址與端口號(hào)。當(dāng)客戶端有一個(gè)以上的IP地址時(shí)摊欠,而且程序員希望直接指定使用的IP地址和端口號(hào)丢烘,可以使用這種方式。如果使用這種方式些椒,必須調(diào)用Connect方法與服務(wù)器建立連接播瞳。例如:
IPAddress[] address = Dns.GetHostAddresses(Dns.GetHostName());
IPEndPoint iep = new IPEndPoint(address[0], 51888);
TcpClient tcpClient = new TcpClient(iep);
tcpClient.Connect("www.abcd.com", 51888);
(4)TcpClient(string hostname,int port)
這是使用最方便的一種構(gòu)造函數(shù)免糕。參數(shù)中的hostname表示要連接到的遠(yuǎn)程主機(jī)的DNS名赢乓,port表示要連接到的遠(yuǎn)程主機(jī)的端口號(hào)痒给。該構(gòu)造函數(shù)會(huì)自動(dòng)分配最合適的本地主機(jī)IP地址和端口號(hào),并對(duì)DNS進(jìn)行解析骏全,然后與遠(yuǎn)程主機(jī)建立連接。例如:
TcpClient tcpClient = new TcpClient("www.abcd.com", 51888);
它相當(dāng)于:
TcpClient tcpClient = new TcpClient();
tcpClient Connect("www.abcd.com",51888);
TcpClient類的常用屬性
TcpClient類的常用方法
TcpClient用法舉例:
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("contosoServer", 11000);
NetworkStream networkStream = tcpClient.GetStream();
networkStream.ReadTimeout = 10;
byte[] bytes = new byte[1024];
networkStream.Read(bytes, 0, 1024);
string data = Encoding.UTF8.GetString(bytes);
networkStream.Close();
tcpClient.Close();
不論是多么復(fù)雜的TCP應(yīng)用程序尼斧,網(wǎng)絡(luò)通信的最基本前提就是客戶端要先和服務(wù)器建立TCP連接姜贡,然后才可以在此基礎(chǔ)上相互傳輸數(shù)據(jù)。由于服務(wù)器需要同時(shí)為多個(gè)客戶端服務(wù)棺棵,因此程序相對(duì)復(fù)雜一些楼咳。
在服務(wù)器端,程序員需要編寫程序不斷地監(jiān)聽(tīng)客戶端是否有連接請(qǐng)求烛恤,一旦接受了客戶端連接請(qǐng)求母怜,即能識(shí)別是哪個(gè)客戶;而客戶端與服務(wù)器連接則相對(duì)比較簡(jiǎn)單缚柏,只需要指定連接哪個(gè)服務(wù)器即可苹熏。一旦雙方建立了連接并創(chuàng)建了對(duì)應(yīng)的套接字,就可以相互傳輸數(shù)據(jù)了币喧。在程序中轨域,發(fā)送和接收數(shù)據(jù)的方法都是一樣的,區(qū)別僅是方向不同杀餐。
編寫服務(wù)器端程序的一般步驟為:
使用對(duì)套接字封裝后的類干发,編寫基于TCP的服務(wù)器端程序的
一般步驟為:
(1)創(chuàng)建一個(gè)TcpListener對(duì)象,然后調(diào)用該對(duì)象的Start方法在指定的端口進(jìn)行監(jiān)聽(tīng)史翘。
(2)在單獨(dú)的線程中枉长,循環(huán)調(diào)用AcceptTcpClient方法接受客戶端的連接請(qǐng)求,并根據(jù)該方法的返回的結(jié)果得到與該客戶端對(duì)應(yīng)的TcpClient對(duì)象琼讽。
(3)每得到一個(gè)新的TcpClient對(duì)象必峰,就創(chuàng)建一個(gè)與該客戶對(duì)應(yīng)的線程,在線程中與對(duì)應(yīng)的客戶進(jìn)行通信钻蹬。
(4)根據(jù)傳送信息的情況確定是否關(guān)閉與客戶的連接自点。
編寫客戶端程序的一般步驟為:
使用對(duì)套接字封裝后的類,編寫基于TCP的客戶端程序的一
般步驟如下:
(1)利用TcpClient的構(gòu)造函數(shù)創(chuàng)建一個(gè)TcpClient對(duì)象脉让。
(2)使用Connect方法與服務(wù)器建立連接桂敛。
(3)利用TcpClient對(duì)象的GetStream方法得到網(wǎng)絡(luò)流,然后利用該網(wǎng)絡(luò)流與服務(wù)器進(jìn)行數(shù)據(jù)傳輸溅潜。
(4)創(chuàng)建一個(gè)線程監(jiān)聽(tīng)指定的端口术唬,循環(huán)接收并處理服務(wù)器發(fā)送過(guò)來(lái)的信息。
(5)完成工作后滚澜,向服務(wù)器發(fā)送關(guān)閉信息粗仓,并關(guān)閉與服務(wù)器的連接。