計(jì)算機(jī)網(wǎng)絡(luò)及TCP網(wǎng)絡(luò)應(yīng)用程序開發(fā)
學(xué)習(xí)目標(biāo)
1、了解計(jì)算機(jī)網(wǎng)絡(luò)相關(guān)信息
2、掌握Python3編碼轉(zhuǎn)換的方法
3、掌握TCP客戶端及服務(wù)器端開發(fā)流程及應(yīng)用實(shí)踐
4、socket套接字之send和recv原理剖析
5、掌握網(wǎng)絡(luò)綜合案例:多任務(wù)版TCP服務(wù)端程序應(yīng)用實(shí)踐
一、計(jì)算機(jī)網(wǎng)絡(luò)概述
1、網(wǎng)絡(luò)的概念
網(wǎng)絡(luò)就是將具有獨(dú)立功能的多臺(tái)計(jì)算機(jī)通過通信線路和通信設(shè)備連接起來,在網(wǎng)絡(luò)管理軟件及網(wǎng)絡(luò)通信協(xié)議下,實(shí)現(xiàn)資源共享和信息傳遞的虛擬平臺(tái)。
2、為什么要學(xué)習(xí)網(wǎng)絡(luò)
學(xué)習(xí)網(wǎng)絡(luò)的目的就是能夠編寫基于網(wǎng)絡(luò)通信的軟件或程序,通常來說就是網(wǎng)絡(luò)編程。

3、IP地址概述
思考一個(gè)問題,當(dāng)我們?cè)谟?jì)算機(jī)中使用微信和你心中那個(gè)“她”聊天時(shí),信息是如何精準(zhǔn)的傳遞到她的計(jì)算機(jī)中的呢?

編輯切換為居中
答:是通過計(jì)算機(jī)的IP地址來實(shí)現(xiàn)的,IP地址是分配給網(wǎng)絡(luò)設(shè)備上網(wǎng)使用的數(shù)字標(biāo)簽,它能夠標(biāo)識(shí)網(wǎng)絡(luò)中唯一的一臺(tái)設(shè)備,好比現(xiàn)實(shí)中每個(gè)人都有一個(gè)手機(jī)號(hào)。

4、IP地址的表現(xiàn)形式

IP地址一共有4位,第1位,1~223,第234位,0~255 IPv4地址是32位二進(jìn)制數(shù),通常用點(diǎn)分十進(jìn)制表示,如192.168.0.1。I Pv6地址是128位二進(jìn)制數(shù),通常用冒號(hào)分隔的16進(jìn)制表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。
注意事項(xiàng):
① IP地址分為兩類 : IPv4和IPv6
② IPv4是目前使用的IP地址
③ IPv6是未來使用的IP地址
5、IP地址的作用
IP地址的作用是用于標(biāo)識(shí)網(wǎng)絡(luò)中的設(shè)備。通過IP地址,網(wǎng)絡(luò)中的設(shè)備可以相互通信,實(shí)現(xiàn)數(shù)據(jù)的傳輸和交換。在互聯(lián)網(wǎng)中,IP地址是唯一的,每個(gè)設(shè)備都有一個(gè)獨(dú)特的IP地址。

6、端口和端口號(hào)的概念
☆ 計(jì)算機(jī)通信原理
問題:如果在一臺(tái)電腦上使用飛秋給另外一臺(tái)電腦上的飛秋發(fā)送數(shù)據(jù)并且另外的這臺(tái)電腦還運(yùn)行著多個(gè)軟件,它是如何區(qū)分這多個(gè)軟件把數(shù)據(jù)給飛秋的呢?

答:其實(shí),每運(yùn)行一個(gè)程序都會(huì)有一個(gè)端口,想要給對(duì)應(yīng)的程序發(fā)送數(shù)據(jù),找到對(duì)應(yīng)的端口即可。端口就是傳輸數(shù)據(jù)的通道,好比教室的門,是數(shù)據(jù)傳輸必經(jīng)之路。

而且每一個(gè)端口都會(huì)有一個(gè)對(duì)應(yīng)的端口號(hào)(操作系統(tǒng)為了統(tǒng)一管理這么多端口,就對(duì)端口進(jìn)行了編號(hào),這就是端口號(hào),端口號(hào)其實(shí)就是一個(gè)數(shù)字,好比我們現(xiàn)實(shí)生活中的門牌號(hào)),想要找到端口通過端口號(hào)即可,如:飛秋軟件的默認(rèn)端口號(hào)就是2345。接收方的飛秋應(yīng)用程序會(huì)監(jiān)聽這個(gè)端口號(hào),從而接收到發(fā)送方發(fā)送的數(shù)據(jù)。其他運(yùn)行的軟件則會(huì)使用不同的端口號(hào)進(jìn)行通信,從而實(shí)現(xiàn)區(qū)分。

最終通信結(jié)果:通過ip地址找到對(duì)應(yīng)的設(shè)備,通過端口號(hào)找到對(duì)應(yīng)的端口,然后通過端口把數(shù)據(jù)給應(yīng)用程序。

☆ 擴(kuò)展:端口號(hào)擴(kuò)展
① 知名端口號(hào)
知名端口號(hào)是指眾所周知的端口號(hào),范圍從0到1023,這些端口號(hào)一般固定分配給一些服務(wù),比如21端口分配給FTP(文件傳輸協(xié)議)服務(wù),22端口分配給SSH(安全外殼協(xié)議,主要用于遠(yuǎn)程連接與文件傳輸),25端口分配給SMTP(簡(jiǎn)單郵件傳輸協(xié)議)服務(wù),80端口分配給HTTP服務(wù),443端口分配給HTTPS服務(wù)等等。
② 動(dòng)態(tài)端口號(hào)
一般程序員開發(fā)應(yīng)用程序使用端口號(hào)稱為動(dòng)態(tài)端口號(hào)。 動(dòng)態(tài)端口號(hào)的范圍是從1024到65535,當(dāng)一個(gè)應(yīng)用程序需要與另一個(gè)應(yīng)用程序進(jìn)行通信時(shí),它會(huì)隨機(jī)選擇一個(gè)動(dòng)態(tài)端口號(hào)作為源端口號(hào),并將目標(biāo)端口號(hào)設(shè)置為對(duì)方應(yīng)用程序所使用的端口號(hào)。這樣可以避免端口號(hào)沖突。當(dāng)通信結(jié)束后,該動(dòng)態(tài)端口號(hào)就會(huì)被釋放,供其他應(yīng)用程序使用。
注意:當(dāng)運(yùn)行一個(gè)程序默認(rèn)會(huì)有一個(gè)端口號(hào),當(dāng)程序退出時(shí),所占用的這個(gè)端口號(hào)就會(huì)被釋放。
設(shè)置端口建議8000以后
7、TCP概述
☆ 為什么需要TCP協(xié)議
之前我們學(xué)習(xí)了IP地址和端口號(hào),通過IP地址能夠找到對(duì)應(yīng)的設(shè)備,然后再通過端口號(hào)找到對(duì)應(yīng)的端口,再通過端口把數(shù)據(jù)傳輸給應(yīng)用程序,這里要注意,數(shù)據(jù)不能隨便發(fā)送,在發(fā)送之前還要選擇網(wǎng)絡(luò)傳輸方式(傳輸協(xié)議),保證程序之間按照指定的傳輸規(guī)則進(jìn)行數(shù)據(jù)的通信。

☆ TCP概述
TCP的英文全拼(Transmission Control Protocol)簡(jiǎn)稱傳輸控制協(xié)議,它是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。

TCP通信步驟:① 創(chuàng)建連接 ?② 傳輸數(shù)據(jù) ?③ 關(guān)閉連接
TCP通信模型相當(dāng)于生活中的’打電話‘,在通信開始之前,一定要先建立好連接,才能發(fā)送數(shù)據(jù),通信結(jié)束要關(guān)閉連接。
☆ TCP的特點(diǎn)
① 面向連接
TCP協(xié)議是一種面向連接的協(xié)議,它需要在數(shù)據(jù)傳輸之前建立連接,數(shù)據(jù)傳輸完成后再關(guān)閉連接。這種面向連接的機(jī)制可以確保數(shù)據(jù)傳輸?shù)捻樞蚝屯暾?,并且可以避免網(wǎng)絡(luò)擁塞和數(shù)據(jù)沖突等問題。

② 可靠傳輸
TCP協(xié)議提供了可靠的數(shù)據(jù)傳輸服務(wù),可以確保數(shù)據(jù)的正確性和完整性。它使用確認(rèn)、重傳和流量控制等機(jī)制來保證數(shù)據(jù)傳輸?shù)目煽啃?,從而避免?shù)據(jù)丟失或損壞。
☆ TCP采用發(fā)送應(yīng)答機(jī)制
通過TCP這種方式發(fā)送的每個(gè)報(bào)文段都必須得到接收方的應(yīng)答才認(rèn)為這個(gè)TCP報(bào)文段傳送成功
☆ 超時(shí)重傳
發(fā)送端發(fā)送一個(gè)報(bào)文之后就會(huì)啟動(dòng)定時(shí)器,如果指定時(shí)間內(nèi)沒有得到應(yīng)答就會(huì)重新發(fā)送這個(gè)報(bào)文段
☆ 錯(cuò)誤校驗(yàn)
TCP用一個(gè)校驗(yàn)和函數(shù)來校驗(yàn)數(shù)據(jù)是否有錯(cuò)誤,在發(fā)送和接收時(shí)都要計(jì)算校驗(yàn)和
☆ 流量控制和阻塞管理
TCP協(xié)議可以根據(jù)網(wǎng)絡(luò)狀況和接收方的處理能力來控制數(shù)據(jù)傳輸?shù)乃俣龋瑥亩苊饩W(wǎng)絡(luò)擁塞和數(shù)據(jù)丟失等問題。它使用滑動(dòng)窗口機(jī)制來實(shí)現(xiàn)流量控制,可以根據(jù)網(wǎng)絡(luò)狀況動(dòng)態(tài)調(diào)整窗口大小。 TCP協(xié)議可以根據(jù)網(wǎng)絡(luò)狀況和擁塞程度來調(diào)整數(shù)據(jù)傳輸?shù)乃俣龋瑥亩苊饩W(wǎng)絡(luò)擁塞和數(shù)據(jù)丟失等問題。它使用擁塞窗口機(jī)制來實(shí)現(xiàn)擁塞控制,可以根據(jù)網(wǎng)絡(luò)狀況動(dòng)態(tài)調(diào)整窗口大小。
擴(kuò)展:UDP協(xié)議(不可靠傳輸協(xié)議)
TCP可靠協(xié)議(數(shù)據(jù)可以100%傳輸)
日常通信、數(shù)據(jù)傳輸一定要保證可靠性,使用TCP。
UDP不可靠協(xié)議(只能保證速度,但是沒辦法保證數(shù)據(jù)傳輸質(zhì)量,發(fā)送5M => 接收3.75M)
有些情況下,我們對(duì)數(shù)據(jù)的質(zhì)量沒有要求,可以考慮使用UDP,如視頻通話。
8、socket套接字
☆ 目前存在的問題
到目前為止我們學(xué)習(xí)了IP地址和端口號(hào),使用這些我們就可以在茫茫的網(wǎng)絡(luò)海洋中進(jìn)行暢游了么? 答案是否定的!

☆ socket套接字
那我們需要什么工具呢?答:socket套接字工具,它是計(jì)算機(jī)之間進(jìn)行通信的一種約定或一種方式。通過 socket 這種約定,Socket是一組用于網(wǎng)絡(luò)通信的API(應(yīng)用程序接口),一臺(tái)計(jì)算機(jī)可以接收其他計(jì)算機(jī)的數(shù)據(jù),也可以向其他計(jì)算機(jī)發(fā)送數(shù)據(jù)。
就好比現(xiàn)實(shí)中的電話,當(dāng)知道了對(duì)方的電話號(hào)碼后需要使用電話才能進(jìn)行通訊,程序之間想要進(jìn)行網(wǎng)絡(luò)通信需要基于這個(gè)socket套接字,socket套接字就是程序間進(jìn)行網(wǎng)絡(luò)通訊的工具。

☆ socket使用場(chǎng)景
不夸張的說,只要跟網(wǎng)絡(luò)相關(guān)的應(yīng)用程序或者軟件都使用到了socket。

二、Python3編碼轉(zhuǎn)換
1、為什么要學(xué)習(xí)編碼轉(zhuǎn)換
在計(jì)算機(jī)網(wǎng)絡(luò)中,數(shù)據(jù)都是以二進(jìn)制的形式進(jìn)行傳輸?shù)?。所以在網(wǎng)絡(luò)傳輸數(shù)據(jù)的時(shí)候,數(shù)據(jù)需要先編碼轉(zhuǎn)化為二進(jìn)制(bytes)數(shù)據(jù)類型 I Love Python => 字符串 => 轉(zhuǎn)換為二進(jìn)制數(shù)據(jù) => 網(wǎng)絡(luò)中傳輸
2、數(shù)據(jù)的編碼轉(zhuǎn)換

數(shù)據(jù)轉(zhuǎn)換方法說明:

提示:encoed()和decode()函數(shù)可以接受參數(shù),encoding是指在編解碼過程中使用的編碼方案。 字符串編碼:
二進(jìn)制解碼:
三、TCP客戶端及服務(wù)器端開發(fā)實(shí)踐
1、TCP網(wǎng)絡(luò)應(yīng)用程序開發(fā)分類
① TCP客戶端應(yīng)用程序開發(fā) ② TCP服務(wù)器端應(yīng)用程序開發(fā) 客戶端程序是指運(yùn)行在用戶設(shè)備上的程序,服務(wù)端程序是指運(yùn)行在服務(wù)器設(shè)備上的程序,專門為客戶端提供數(shù)據(jù)服務(wù)。那如何記憶呢?
主動(dòng)發(fā)起建立連接請(qǐng)求的是客戶端程序,等待接受連接請(qǐng)求的是服務(wù)端程序。
2、TCP客戶端程序開發(fā)流程及應(yīng)用實(shí)踐(五步走)
☆ 開發(fā)流程介紹

TCP客戶端程序開發(fā)流程及應(yīng)用實(shí)踐通??梢苑譃槲宀阶?,具體如下:
1、創(chuàng)建Socket對(duì)象:客戶端程序需要使用Socket API創(chuàng)建一個(gè)Socket對(duì)象,以便與服務(wù)器進(jìn)行連接和通信。創(chuàng)建Socket對(duì)象的代碼通常如下:
其中,socket.AF_INET表示使用IPv4協(xié)議進(jìn)行通信,socket.SOCK_STREAM表示使用TCP協(xié)議進(jìn)行通信。
2、連接服務(wù)器:客戶端程序需要使用Socket API調(diào)用connect()函數(shù)連接到服務(wù)器,以便進(jìn)行數(shù)據(jù)的傳輸和通信。連接服務(wù)器的代碼通常如下:
其中,server_address表示服務(wù)器的地址和端口號(hào)。
3、發(fā)送請(qǐng)求:客戶端程序需要向服務(wù)器發(fā)送請(qǐng)求,以便獲取服務(wù)器的響應(yīng)數(shù)據(jù)。請(qǐng)求的格式通常由應(yīng)用程序自己定義,可以使用XML、JSON等格式進(jìn)行數(shù)據(jù)的傳輸和解析。發(fā)送請(qǐng)求的代碼通常如下:
其中,request_data表示發(fā)送的請(qǐng)求數(shù)據(jù),使用encode()函數(shù)將字符串轉(zhuǎn)換為字節(jié)流進(jìn)行發(fā)送。
4、接收響應(yīng):客戶端程序需要等待服務(wù)器的響應(yīng),并使用recv()函數(shù)接收服務(wù)器返回的數(shù)據(jù)。響應(yīng)數(shù)據(jù)的格式通常由應(yīng)用程序自己定義,可以使用XML、JSON等格式進(jìn)行數(shù)據(jù)的傳輸和解析。接收響應(yīng)的代碼通常如下:
其中,1024表示一次最多接收的字節(jié)數(shù),使用decode()函數(shù)將接收到的字節(jié)流轉(zhuǎn)換為字符串進(jìn)行處理。
5、關(guān)閉連接:客戶端程序在完成數(shù)據(jù)傳輸后,需要使用Socket API關(guān)閉連接,并釋放相關(guān)的資源。關(guān)閉連接的代碼通常如下:
以上是TCP客戶端程序開發(fā)流程及應(yīng)用實(shí)踐的五個(gè)步驟,通過這些步驟可以實(shí)現(xiàn)客戶端與服務(wù)器之間的數(shù)據(jù)傳輸和通信。
☆ socket類的介紹
① 導(dǎo)入socket模塊import socket?
② 創(chuàng)建客戶端socket對(duì)象使用socket類 socket.socket(AddressFamily, Type)
客戶端socket類的參數(shù)和方法說明:

開發(fā)客戶端需要使用的函數(shù):

☆ TCP客戶端程序開發(fā)實(shí)踐
使用網(wǎng)絡(luò)調(diào)試查看,效果如下圖所示:

3、TCP服務(wù)器端開發(fā)流程及應(yīng)用實(shí)踐(七步走)
☆ 服務(wù)器端

☆ 開發(fā)流程介紹

TCP服務(wù)器端開發(fā)流程及應(yīng)用實(shí)踐一般分為七個(gè)步驟,具體如下:
1.創(chuàng)建Socket對(duì)象:服務(wù)器程序需要使用Socket API創(chuàng)建一個(gè)Socket對(duì)象,以便監(jiān)聽客戶端的連接請(qǐng)求。創(chuàng)建Socket對(duì)象的代碼通常如下:
其中,socket.AF_INET表示使用IPv4協(xié)議進(jìn)行通信,socket.SOCK_STREAM表示使用TCP協(xié)議進(jìn)行通信。
2.綁定地址和端口號(hào):服務(wù)器程序需要使用Socket API調(diào)用bind()函數(shù)將Socket對(duì)象綁定到一個(gè)特定的IP地址和端口號(hào)上,以便客戶端可以連接到服務(wù)器。綁定地址和端口號(hào)的代碼通常如下:
其中,server_address表示服務(wù)器的地址和端口號(hào)。
3.監(jiān)聽連接請(qǐng)求:服務(wù)器程序需要使用Socket API調(diào)用listen()函數(shù)開始監(jiān)聽客戶端的連接請(qǐng)求,以便客戶端可以連接到服務(wù)器進(jìn)行通信。監(jiān)聽連接請(qǐng)求的代碼通常如下:
其中,5表示最大連接數(shù)。
4.接受連接:服務(wù)器程序需要使用Socket API調(diào)用accept()函數(shù)接受客戶端的連接請(qǐng)求,并返回一個(gè)新的Socket對(duì)象,以便服務(wù)器與客戶端進(jìn)行數(shù)據(jù)的傳輸和通信。接受連接的代碼通常如下:
其中,client_socket表示與客戶端進(jìn)行通信的Socket對(duì)象,client_address表示客戶端的地址和端口號(hào)。
5.接收請(qǐng)求:服務(wù)器程序需要使用Socket API調(diào)用recv()函數(shù)接收客戶端發(fā)送的請(qǐng)求數(shù)據(jù),并進(jìn)行處理。請(qǐng)求數(shù)據(jù)的格式通常由應(yīng)用程序自己定義,可以使用XML、JSON等格式進(jìn)行數(shù)據(jù)的傳輸和解析。接收請(qǐng)求的代碼通常如下:
其中,1024表示一次最多接收的字節(jié)數(shù),使用decode()函數(shù)將接收到的字節(jié)流轉(zhuǎn)換為字符串進(jìn)行處理。
6.發(fā)送響應(yīng):服務(wù)器程序需要向客戶端發(fā)送響應(yīng)數(shù)據(jù),以便客戶端可以獲取服務(wù)器的處理結(jié)果。響應(yīng)數(shù)據(jù)的格式通常由應(yīng)用程序自己定義,可以使用XML、JSON等格式進(jìn)行數(shù)據(jù)的傳輸和解析。發(fā)送響應(yīng)的代碼通常如下:
其中,response_data表示發(fā)送的響應(yīng)數(shù)據(jù),使用encode()函數(shù)將字符串轉(zhuǎn)換為字節(jié)流進(jìn)行發(fā)送。
7.關(guān)閉連接:服務(wù)器程序在完成數(shù)據(jù)傳輸后,需要使用Socket API關(guān)閉連接,并釋放相關(guān)的資源。關(guān)閉連接的代碼通常如下:
以上是TCP服務(wù)器端程序開發(fā)流程及應(yīng)用實(shí)踐的七個(gè)步驟,通過這些步驟可以實(shí)現(xiàn)服務(wù)器與客戶端之間的數(shù)據(jù)傳輸和通信。
☆ socket類的介紹
客戶端socket類的參數(shù)和方法說明:

開發(fā)客戶端需要使用的函數(shù):
客戶端socket類的參數(shù)和方法說明:

開發(fā)服務(wù)器端需要使用的函數(shù):

☆ TCP服務(wù)器端程序開發(fā)實(shí)踐
這段代碼是一個(gè)簡(jiǎn)單的TCP服務(wù)器程序,主要實(shí)現(xiàn)了接收服務(wù)器端的數(shù)據(jù),并返回一個(gè)確認(rèn)消息:
首先,導(dǎo)入Python標(biāo)準(zhǔn)庫(kù)中的 socket 模塊,用于實(shí)現(xiàn)TCP套接字的編程。
然后,在if name == 'main':語句塊中,創(chuàng)建了一個(gè)TCP服務(wù)器端套接字對(duì)象 tcp_server_socket,并使用bind()方法將其綁定到本地IP地址和端口號(hào)8888上,使用listen()方法設(shè)置最大連接數(shù)為128,即最多可以同時(shí)處理128個(gè)客戶端的連接請(qǐng)求。
接著,使用accept()方法阻塞等待客戶端的連接請(qǐng)求,當(dāng)客戶端連接成功后,該方法會(huì)返回一個(gè)新的客戶端套接字對(duì)象 conn_socket 和客戶端IP地址和端口號(hào) ip_port。
然后,使用recv()方法接收客戶端的數(shù)據(jù),該方法的參數(shù)是接收數(shù)據(jù)的最大長(zhǎng)度,返回值是一個(gè)字節(jié)流。使用decode()方法將字節(jié)流解碼為字符串后打印出來。 接下來,使用send()方法向客戶端發(fā)送一個(gè)確認(rèn)消息,使用字符編碼轉(zhuǎn)換將字符串轉(zhuǎn)換為字節(jié)流再發(fā)送。
最后,使用close()方法分別關(guān)閉服務(wù)器端套接字 tcp_server_socket 和客戶端套接字對(duì)象 conn_socket,釋放資源。
4、TCP服務(wù)器端開發(fā)面向?qū)ο蟀姹?/p>
下面再通過一個(gè)實(shí)例來實(shí)現(xiàn)一一個(gè)基于TCP協(xié)議的簡(jiǎn)單的Web服務(wù)器。
首先,該代碼導(dǎo)入了Python的socket模塊,用于實(shí)現(xiàn)TCP套接字的編程。
然后,定義了一個(gè) WebServer 類,該類包含 ?__init __() 方法用于對(duì)象初始化,start() 方法用于啟動(dòng)WebServer監(jiān)聽客戶端連接,以及handle_client_request() 方法用于接受和處理客戶端的請(qǐng)求。
在 init() 方法中,該服務(wù)器首先創(chuàng)建了一個(gè)TCP套接字對(duì)象 tcp_server_socket,并使用 bind() 方法將其綁定到本地IP地址及端口號(hào)8090上,然后使用 listen() 方法進(jìn)行監(jiān)聽客戶端的連接。
在 handle_client_request() 方法中,服務(wù)器接收客戶端的請(qǐng)求消息,然后發(fā)送響應(yīng)消息。
在 start() 方法中,服務(wù)器不斷循環(huán)等待客戶端的連接,接收連接后調(diào)用 handle_client_request() 方法進(jìn)行請(qǐng)求處理。
最后,在程序執(zhí)行入口中,實(shí)例化 WebServer 類生成對(duì)象,并調(diào)用 start() 方法啟動(dòng)WebServer。
這段代碼的作用是在本地啟動(dòng)一個(gè)WebServer服務(wù)器端,并監(jiān)聽8080端口上的客戶端連接。當(dāng)有客戶端連接到服務(wù)器后,服務(wù)器將接收客戶端的請(qǐng)求消息并返回響應(yīng)消息。
5、擴(kuò)展:TCP服務(wù)器端開發(fā)之多客戶端
這段代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的TCP服務(wù)器,可以收發(fā)文本消息。
首先,該代碼導(dǎo)入Python的socket模塊,用于實(shí)現(xiàn)TCP套接字的編程。 然后,創(chuàng)建一個(gè)TCP套接字對(duì)象 tcp_server_socket,并使用 bind() 方法將其綁定到本地IP地址及端口號(hào)8090上,使用 listen() 方法設(shè)置最大連接數(shù)為128,即最多可以同時(shí)處理128個(gè)客戶端的連接請(qǐng)求。
接著,在一個(gè)無限循環(huán)中等待客戶端連接,在每次客戶端連接成功之后,使用 accept() 方法接受連接請(qǐng)求,返回一個(gè)新的客戶端套接字對(duì)象 new_socket 和客戶端IP地址和端口號(hào) ip_port。
接下來,通過一個(gè)while循環(huán)不斷地接收客戶端發(fā)送過來的消息,使用 recv() 方法接收消息,使用 decode() 方法將接收到的字節(jié)流轉(zhuǎn)換為字符串進(jìn)行處理,并使用 print() 方法打印消息內(nèi)容。
然后,通過 input() 函數(shù)讓服務(wù)器輸入響應(yīng)消息,將響應(yīng)消息使用 encode() 方法轉(zhuǎn)換為字節(jié)流后,使用 send() 方法發(fā)送給客戶端。 當(dāng)客戶端斷開連接時(shí),會(huì)拋出 ConnectionResetError 異常,這時(shí)我們使用 break 語句跳出循環(huán),等待下一個(gè)客戶端連接。
最后,當(dāng)出現(xiàn)異常時(shí),通過 try... except... 語句來捕獲異常并退出服務(wù)器監(jiān)聽狀態(tài),并使用 close() 方法關(guān)閉服務(wù)器套接字。 總之,這段代碼使用了Python的 socket 模塊實(shí)現(xiàn)了TCP服務(wù)器的監(jiān)聽功能,能夠接收來自客戶端的文本消息,并向客戶端發(fā)送響應(yīng)消息。
6、TCP網(wǎng)絡(luò)應(yīng)用程序開發(fā)注意點(diǎn)
1.當(dāng)TCP客戶端程序想要和TCP服務(wù)端程序進(jìn)行通信的時(shí)候必須要先建立連接。 ?
2.TCP客戶端程序一般不需要綁定端口號(hào),因?yàn)榭蛻舳耸侵鲃?dòng)發(fā)起建立連接的。 ?
3.否則客戶端找不到這個(gè)TCP服務(wù)端程序。TCP服務(wù)端程序必須綁定端口號(hào)。 ?
4.listen后的套接字是被動(dòng)套接字,只負(fù)責(zé)接收新的客戶端的連接請(qǐng)求,不能收發(fā)消息。 ?
5.當(dāng)TCP客戶端程序和TCP服務(wù)端程序連接成功后,TCP服務(wù)器端程序會(huì)產(chǎn)生一個(gè)新的套接字,收發(fā)客戶端消息使用該套接字。 ?
6.關(guān)閉accept返回的套接字意味著和這個(gè)客戶端已經(jīng)通信完畢。 ?
7.當(dāng)客戶端的套接字調(diào)用close后,服務(wù)器端的recv會(huì)解阻塞,返回的數(shù)據(jù)長(zhǎng)度為0。服務(wù)端可以通過返回?cái)?shù)據(jù)的長(zhǎng)度來判斷客戶端是否已經(jīng)下線,反之,服務(wù)端關(guān)閉套接字,客戶端的recv也會(huì)解阻塞,返回的數(shù)據(jù)長(zhǎng)度也為0。
端口復(fù)用:
這段代碼與前一段代碼類似,是一個(gè)簡(jiǎn)單的TCP服務(wù)器程序。與前一段代碼不同的是,在創(chuàng)建服務(wù)器端套接字對(duì)象之后,設(shè)置了端口復(fù)用。詳細(xì)解釋一下:
首先,導(dǎo)入Python標(biāo)準(zhǔn)庫(kù)中的 socket 模塊,用于實(shí)現(xiàn)TCP套接字的編程。
然后,在if name == 'main':語句塊中,創(chuàng)建了一個(gè)TCP服務(wù)器端套接字對(duì)象 tcp_server_socket,并使用bind()方法將其綁定到本地IP地址和端口號(hào)8888上,使用listen()方法設(shè)置最大連接數(shù)為128,即最多可以同時(shí)處理128個(gè)客戶端的連接請(qǐng)求。
接著,使用setsockopt()方法設(shè)置了端口復(fù)用選項(xiàng)。端口復(fù)用是指一個(gè)端口可以被多個(gè)應(yīng)用程序占用,這樣可以避免端口資源的浪費(fèi)。在這里,使用SOL_SOCKET和SO_REUSEADDR選項(xiàng)來設(shè)置端口復(fù)用。
接下來,使用accept()方法阻塞等待客戶端的連接請(qǐng)求,當(dāng)客戶端連接成功后,該方法會(huì)返回一個(gè)新的客戶端套接字對(duì)象 conn_socket 和客戶端IP地址和端口號(hào) ip_port。
然后,使用recv()方法接收客戶端的數(shù)據(jù),該方法的參數(shù)是接收數(shù)據(jù)的最大長(zhǎng)度,返回值是一個(gè)字節(jié)流。使用decode()方法將字節(jié)流解碼為字符串后打印出來。
接下來,使用send()方法向客戶端發(fā)送一個(gè)確認(rèn)消息,使用字符編碼轉(zhuǎn)換將字符串轉(zhuǎn)換為字節(jié)流再發(fā)送。
最后,使用close()方法分別關(guān)閉服務(wù)器端套接字 tcp_server_socket 和客戶端套接字對(duì)象 conn_socket,釋放資源。 總之,這段代碼與前一段代碼類似,是一個(gè)簡(jiǎn)單的TCP服務(wù)器程序,它除了設(shè)置了端口復(fù)用之外,并且能夠接收客戶端的數(shù)據(jù),并返回一個(gè)確認(rèn)消息。