版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第13章網(wǎng)絡(luò)編程《Python程序開發(fā)案例教程(第2版))》學(xué)習(xí)目標(biāo)/Target
了解協(xié)議與體系結(jié)構(gòu),能夠說出五層協(xié)議體系結(jié)構(gòu)中各層的功能,區(qū)分TCP協(xié)議和UDP協(xié)議的特點了解數(shù)據(jù)傳輸流程,能夠說出兩個進程通信的數(shù)據(jù)傳輸流程了解網(wǎng)絡(luò)架構(gòu),能夠說出C/S架構(gòu)和B/S架構(gòu)的特點了解IP地址和端口號,能夠說出它們的作用及特點掌握socket套接字的創(chuàng)建方式,能夠通過socket()方法創(chuàng)建基于TCP通信的流式套接字學(xué)習(xí)目標(biāo)/Target
熟悉socket通信流程,能夠歸納面向連接通信和面向非連接通信的流程
掌握socket內(nèi)置方法,能夠通過這些方法實現(xiàn)socket通信掌握基于UDP的網(wǎng)絡(luò)聊天室功能,能夠?qū)崿F(xiàn)基于UDP的網(wǎng)絡(luò)聊天室掌握基于TCP的數(shù)據(jù)轉(zhuǎn)換功能,能夠?qū)崿F(xiàn)基于TCP的數(shù)據(jù)轉(zhuǎn)換
掌握并發(fā)服務(wù)器,能夠?qū)崿F(xiàn)單進程非阻塞服務(wù)器、多進程并發(fā)服務(wù)器以及多線程并發(fā)服務(wù)器章節(jié)概述/Summary隨著計算機與互聯(lián)網(wǎng)的普及和發(fā)展,網(wǎng)絡(luò)已經(jīng)廣泛滲透到社會生活的各個方面,無論是操作系統(tǒng)還是手機應(yīng)用,都與網(wǎng)絡(luò)密切相關(guān)。網(wǎng)絡(luò)編程是Python學(xué)習(xí)中的一個關(guān)鍵環(huán)節(jié),它能夠幫助讀者理解網(wǎng)絡(luò)通信的工作原理,實現(xiàn)高效的數(shù)據(jù)交換,掌握構(gòu)建高效可靠的網(wǎng)絡(luò)應(yīng)用程序的技能。本章將對Python中網(wǎng)絡(luò)編程的相關(guān)知識進行講解。目錄/Contents010203網(wǎng)絡(luò)概述socket網(wǎng)絡(luò)編程基礎(chǔ)基于UDP的網(wǎng)絡(luò)聊天室目錄/Contents040506基于TCP的數(shù)據(jù)轉(zhuǎn)換實例2:TCP文件下載TCP并發(fā)服務(wù)器網(wǎng)絡(luò)概述13.1
先定一個小目標(biāo)!了解協(xié)議與體系結(jié)構(gòu),能夠說出五層協(xié)議體系結(jié)構(gòu)中各層的功能,區(qū)分TCP協(xié)議和UDP協(xié)議的特點13.1.1協(xié)議與體系結(jié)構(gòu)協(xié)議網(wǎng)絡(luò)中存在多臺主機,為保證主機間能順利通訊,且通信雙方可以獲取到準(zhǔn)確、有效的數(shù)據(jù),應(yīng)制訂一組用于數(shù)據(jù)傳輸?shù)囊?guī)則,這組規(guī)則就是協(xié)議。13.1.1協(xié)議與體系結(jié)構(gòu)1.網(wǎng)絡(luò)體系結(jié)構(gòu)計算機網(wǎng)絡(luò)中常見的體系結(jié)構(gòu)有OSI(開放式系統(tǒng)互聯(lián)模型)和TCP/IP(傳輸控制協(xié)議/互聯(lián)網(wǎng)協(xié)議模型)。OSI由國際標(biāo)準(zhǔn)協(xié)會ISO制定,共分為七層,由上而下依次為應(yīng)用層、表示層、會話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層和物理層,雖然OSI由ISO制定,但其實用性較差,并未得到廣泛應(yīng)用。13.1.1協(xié)議與體系結(jié)構(gòu)1.網(wǎng)絡(luò)體系結(jié)構(gòu)在OSI誕生時,因特網(wǎng)已實現(xiàn)了全世界的基本覆蓋,因此市面上應(yīng)用最廣泛的體系結(jié)構(gòu)為因特網(wǎng)中使用的TCP/IP體系結(jié)構(gòu),該結(jié)構(gòu)包含四層,分別為應(yīng)用層、傳輸層、網(wǎng)際層和網(wǎng)絡(luò)接口層。13.1.1協(xié)議與體系結(jié)構(gòu)1.網(wǎng)絡(luò)體系結(jié)構(gòu)13.1.1協(xié)議與體系結(jié)構(gòu)在計算機網(wǎng)絡(luò)中通常以一種包含五層協(xié)議的體系結(jié)構(gòu)來講解各層之間的功能與聯(lián)系,這種體系結(jié)構(gòu)結(jié)合OSI和TCP/IP的優(yōu)點,分為應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層和物理層。物理層:計算機體系結(jié)構(gòu)的最底層,它為設(shè)備之間的數(shù)據(jù)傳輸提供可靠的環(huán)境。數(shù)據(jù)鏈路層:簡稱鏈路層,它將從網(wǎng)絡(luò)層獲取的數(shù)據(jù)報組裝成幀,在網(wǎng)絡(luò)結(jié)點之間以幀為單位傳輸數(shù)據(jù)。網(wǎng)絡(luò)層:為分組交換網(wǎng)上的不同主機提供通信服務(wù)。在進行通信時,網(wǎng)絡(luò)層會將從傳輸層獲取的報文段或數(shù)據(jù)報進行封裝,形成分組或包。這些數(shù)據(jù)或包通常被稱為數(shù)據(jù)報。傳輸層:為應(yīng)用進程提供連接服務(wù),實現(xiàn)連接兩端進程的會話。應(yīng)用層:為應(yīng)用進程提供服務(wù),定義了應(yīng)用進程間通信和交互的規(guī)則。1.網(wǎng)絡(luò)體系結(jié)構(gòu)13.1.1協(xié)議與體系結(jié)構(gòu)OSI、TCP/IP和五層協(xié)議體系結(jié)構(gòu)各層對應(yīng)關(guān)系。13.1.1協(xié)議與體系結(jié)構(gòu)2.協(xié)議計算機網(wǎng)絡(luò)通信基于TCP/IP,TCP/IP實際上是協(xié)議族,它由多種協(xié)議構(gòu)成,包括TCP協(xié)議、UDP協(xié)議、IP協(xié)議等等,其中TCP、UDP協(xié)議應(yīng)用在傳輸層;IP協(xié)議應(yīng)用在網(wǎng)絡(luò)層。TCP協(xié)議即傳輸控制協(xié)議(TransmissionControlProtocol),該協(xié)議是一種面向連接的、可靠的、基于字節(jié)流的傳輸協(xié)議。在傳遞數(shù)據(jù)之前,收發(fā)雙方會先通過一種被稱為“三次握手”的協(xié)商機制建立連接,為數(shù)據(jù)傳輸做好準(zhǔn)備。為了防止報文段丟失,TCP會給每個數(shù)據(jù)段一個序號,使接收端按序號順序接收數(shù)據(jù)。若接收端正常接收到報文段,向發(fā)送端發(fā)送一個確認信息;若發(fā)送端在一定的時延后未接收到確認信息,便假設(shè)報文段已丟失,并重新向接收端發(fā)送對應(yīng)報文段。此外,TCP協(xié)議中定義了一個校驗函數(shù),用于檢測發(fā)送和接收的數(shù)據(jù),防止產(chǎn)生數(shù)據(jù)錯誤。13.1.1協(xié)議與體系結(jié)構(gòu)TCP協(xié)議13.1.1協(xié)議與體系結(jié)構(gòu)TCP協(xié)議通信結(jié)束后,通信雙方經(jīng)過“四次握手”關(guān)閉連接。因為TCP連接是全雙工的,全雙工是指交換機在發(fā)送數(shù)據(jù)的同時也能夠接收數(shù)據(jù),兩者同步進行,類似語音通話,雙方在說話的同時也能夠聽到對方的聲音,所以每個方向必須單獨關(guān)閉連接,即連接的一端需先發(fā)送關(guān)閉信息到另一端,當(dāng)關(guān)閉信息發(fā)送后,發(fā)送關(guān)閉信息的一端不會再發(fā)送信息,但另一端仍可向該端發(fā)送信息。13.1.1協(xié)議與體系結(jié)構(gòu)UDP協(xié)議UDP協(xié)議即用戶數(shù)據(jù)報協(xié)議,它是一種無連接的傳輸層協(xié)議。UDP的收發(fā)雙方?jīng)]有建立連接,當(dāng)按照UDP協(xié)議傳輸數(shù)據(jù)時,發(fā)送方使用套接字文件發(fā)送數(shù)據(jù)報給接收方,之后可立即使用同一個套接字發(fā)送其他數(shù)據(jù)報給另一個接收方;同樣的,接收方也可以通過相同的套接字接收由多個發(fā)送方發(fā)來的數(shù)據(jù)。13.1.1協(xié)議與體系結(jié)構(gòu)UDP協(xié)議UDP不對數(shù)據(jù)報進行編號,它不保證接收方以正確的順序接收到完整的數(shù)據(jù),但會將數(shù)據(jù)報的長度隨數(shù)據(jù)發(fā)送給接收方。雖然UDP面向無連接的通信,不能如TCP般很好地保證數(shù)據(jù)的完整性和正確性,但UDP處理速度快,耗費資源少,因此在對數(shù)據(jù)完整性要求低、對傳輸效率要求高的應(yīng)用中一般使用UDP協(xié)議傳輸數(shù)據(jù)。13.1.1協(xié)議與體系結(jié)構(gòu)IP協(xié)議IP協(xié)議的兩個基本功能為尋址和分段。傳輸層的數(shù)據(jù)封裝完成后沒有直接發(fā)送到接收方,而是先遞達網(wǎng)絡(luò)層;網(wǎng)絡(luò)層又在原數(shù)據(jù)報前添加IP首部,封裝成IP數(shù)據(jù)報,并解析數(shù)據(jù)報中的目的地址,為其選擇傳輸路徑,將數(shù)據(jù)報發(fā)送到接收方。IP協(xié)議中這種選擇傳輸路徑的功能稱為路由功能。此外,IP協(xié)議可重新組裝數(shù)據(jù)報,改變數(shù)據(jù)報的大小,以適應(yīng)不同網(wǎng)絡(luò)對數(shù)據(jù)包大小的要求。需要說明的是,IP協(xié)議不提供端到端或結(jié)點到結(jié)點的確認,只檢測報頭中的校驗碼,不提供可靠的傳輸服務(wù)。13.1.1協(xié)議與體系結(jié)構(gòu)IP協(xié)議雖然各層使用的協(xié)議互不相同,但協(xié)議通常都由以下3個部分組成:①待交互數(shù)據(jù)的結(jié)構(gòu)和格式;②進行交互的方式,包括數(shù)據(jù)的類型、對數(shù)據(jù)的處理動作等;③事件實現(xiàn)順序的說明。一組完整的協(xié)議不僅需要考慮通信雙方在正常情況下的動作,還應(yīng)考慮到通信時可能出現(xiàn)的異常,并對異常情況下通信雙方的動作做出規(guī)定。
先定一個小目標(biāo)!了解數(shù)據(jù)傳輸流程,能夠說出兩個進程通信的數(shù)據(jù)傳輸流程13.1.2數(shù)據(jù)傳輸流程數(shù)據(jù)傳輸流程13.1.2數(shù)據(jù)傳輸流程數(shù)據(jù)傳輸流程13.1.2數(shù)據(jù)傳輸流程數(shù)據(jù)傳輸流程兩個進程進行通信時,數(shù)據(jù)傳輸流程以及數(shù)據(jù)的變化情況如下:(1)來自一個進程的數(shù)據(jù)遞達應(yīng)用層,應(yīng)用層根據(jù)本層協(xié)議在數(shù)據(jù)的頭部添加相應(yīng)控制信息h5,之后將數(shù)據(jù)傳向傳輸層。(2)傳輸層接收來自應(yīng)用層的信息,并通過TCP協(xié)議或UDP協(xié)議添加控制信息h4(TCP首部或UDP首部),添加完成后作為數(shù)據(jù)段或數(shù)據(jù)包傳向網(wǎng)絡(luò)層。(3)網(wǎng)絡(luò)層接收來自傳輸層的數(shù)據(jù)段或數(shù)據(jù)包,為其添加控制信息h3(IP首部)并封裝為IP數(shù)據(jù)報,傳遞到數(shù)據(jù)鏈路層。13.1.2數(shù)據(jù)傳輸流程數(shù)據(jù)傳輸流程兩個進程進行通信時,數(shù)據(jù)傳輸流程以及數(shù)據(jù)的變化情況如下:(4)數(shù)據(jù)鏈路層接收到來自網(wǎng)絡(luò)層的IP數(shù)據(jù)報,在IP數(shù)據(jù)報的頭部和尾部分別添加控制信息h2,封裝成數(shù)據(jù)幀并傳遞到物理層。(5)物理層接收到來自數(shù)據(jù)鏈路層的數(shù)據(jù)幀,將其轉(zhuǎn)化為由0、1代碼組成的比特流,再傳送到物理傳輸媒介。(6)物理傳輸媒介中的比特流經(jīng)路由轉(zhuǎn)發(fā),首先遞達另一個進程所在的物理傳輸媒介中,然后按照TCP/IP協(xié)議族中的協(xié)議,將比特流格式的數(shù)據(jù)轉(zhuǎn)換為數(shù)據(jù)幀,依次去除數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層和應(yīng)用層添加的控制信息,最后將原始數(shù)據(jù)傳送給另一個進程。體系結(jié)構(gòu)中各層的實現(xiàn)建立在其下一層所提供的服務(wù)上,且本層繼續(xù)向上層提供服務(wù),各層之間的常用協(xié)議以及層級關(guān)系如圖所示。13.1.2數(shù)據(jù)傳輸流程數(shù)據(jù)傳輸流程
先定一個小目標(biāo)!了解網(wǎng)絡(luò)架構(gòu),能夠說出C/S架構(gòu)和B/S架構(gòu)的特點13.1.3網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)架構(gòu)13.1.3網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)架構(gòu)分為C/S架構(gòu)和B/S架構(gòu),其中C/S架構(gòu)即客戶機(Client)/服務(wù)器(Server)模式,這種架構(gòu)需要在進行通信的兩端分別架設(shè)客戶機和服務(wù)器,常見的基于C/S架構(gòu)的有銀行系統(tǒng)中的ATM機、打印店中的電腦與打印機等;B/S架構(gòu)是瀏覽器(Browser)/服務(wù)器(Server)架構(gòu),這是WEB(WorldWideWeb,萬維網(wǎng))興起后的一種網(wǎng)絡(luò)架構(gòu),客戶機只需安裝瀏覽器,便可與服務(wù)器進行交互,常見的B/S架構(gòu)如百度、谷歌等瀏覽器建設(shè)、大多學(xué)校使用的校園網(wǎng),以及公司內(nèi)網(wǎng)等。C/S架構(gòu)與B/S架構(gòu)示意圖如圖所示。13.1.3網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)架構(gòu)這兩種網(wǎng)絡(luò)架構(gòu)都符合客戶端/服務(wù)器模式,它們最大的區(qū)別在于客戶端是否需要特定的硬件支持。網(wǎng)絡(luò)架構(gòu)13.1.3網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)架構(gòu)中的客戶端主動發(fā)出請求,服務(wù)器被動地提供服務(wù)。服務(wù)器一般需要永久運行,以便能隨時接收并處理用戶請求;而客戶端只在需要時啟動??蛻舳?服務(wù)器之間可以是一對一、多對一的關(guān)系,也可以是多對多的關(guān)系。
先定一個小目標(biāo)!了解IP地址和端口號,能夠說出它們的作用及特點13.1.4IP地址和端口號1.IP地址IP地址用于在網(wǎng)絡(luò)上標(biāo)記唯一一臺計算機。網(wǎng)絡(luò)中包含多個小型的網(wǎng)絡(luò)與眾多主機,若主機pc1要向主機pc2發(fā)送信息,那么pc1必須能在這個網(wǎng)絡(luò)中找到pc2,這要求pc2在整個網(wǎng)絡(luò)中有一個唯一標(biāo)識,這個每臺主機在網(wǎng)絡(luò)中的唯一標(biāo)識就是IP地址。13.1.4IP地址和端口號1.IP地址由于使用四個字段表示的IP地址難以閱讀和記憶,人們發(fā)明了域名系統(tǒng),域名系統(tǒng)中的每個域名都對應(yīng)唯一一個IP地址,即使用域名或者與域名對應(yīng)的IP地址可以訪問網(wǎng)絡(luò)上的同一臺主機。例如,使用域名“”或者IP地址“4”都能訪問百度的主機。域名和IP地址也被稱為主機名(hostname)。13.1.4IP地址和端口號2.端口號IP地址只能確定網(wǎng)絡(luò)中的主機,要確定主機中的進程,還需用到端口號(port)。在計算機網(wǎng)絡(luò)中,端口號是一臺主機中進程的唯一標(biāo)識,因此一個進程在向另一個進程發(fā)送數(shù)據(jù)時,要使用“IP地址+端口號”確定網(wǎng)絡(luò)中的唯一進程。端口號的最大取值為65535,其中0~1024號端口一般由系統(tǒng)進程占用,用戶可到網(wǎng)絡(luò)相關(guān)資料上查看由國際因特網(wǎng)地址分配委員會維護的官方已分配的端口列表。用戶在編寫自己的服務(wù)器時,可以選擇一個大于1024、小于65535的端口號來標(biāo)識自己的服務(wù)器,但要注意選擇空閑的端口號,避免與其他服務(wù)器產(chǎn)生沖突。13.1.4IP地址和端口號socket網(wǎng)絡(luò)編程基礎(chǔ)13.2
先定一個小目標(biāo)!掌握socket套接字的創(chuàng)建方式,能夠通過socket()方法創(chuàng)建基于TCP通信的流式套接字13.2.1socket套接字socket()方法Python有一個名為socket的模塊,該模塊包含了網(wǎng)絡(luò)編程的類、方法、函數(shù)等。利用socket模塊中的構(gòu)造方法socket()可以創(chuàng)建一個socket對象,socket()方法的語法格式下:socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)語法格式13.2.1socket套接字family:用于指定地址族,默認值為AF_INET,表示可用于地址為IPv4格式的進程間通信。type:用于指定socket的類型,該參數(shù)決定socket的通信方式。proto:用于指定與特定的地址族相關(guān)的協(xié)議,默認值為0,表示由系統(tǒng)根據(jù)地址格式和套接字類型自動選擇合適的協(xié)議。fileno:用于為套接字文件設(shè)置文件描述符,默認設(shè)置為None,表示由系統(tǒng)分配。通過socket()方法創(chuàng)建socket對象,示例代碼如下:importsocket#創(chuàng)建socket對象,指定socket的類型為流式套接字socket_tcp=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創(chuàng)建socket對象,指定socket的類型為數(shù)據(jù)報式套接字socket_udp=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)示例13.2.1socket套接字socket()方法
先定一個小目標(biāo)!掌握socket套接字的創(chuàng)建方式,能夠通過socket()方法創(chuàng)建基于TCP通信的流式套接字13.2.2socket通信流程1.面向連接的通信13.2.2socket通信流程根據(jù)socket的類型,網(wǎng)絡(luò)通信又分為基于TCP協(xié)議、面向連接的通信和基于UDP、面向無連接的通信。面向連接的通信類似日常生活中的電話服務(wù)。在電話服務(wù)中,接電話的一方需要保持電話暢通,以便可隨時接收他人發(fā)送的通話請求;在電話連通之后,通話的雙方可以開始交換數(shù)據(jù)。1.面向連接的通信13.2.2socket通信流程面向連接的通信流程如圖所示。1.面向連接的通信13.2.2socket通信流程在面向連接的通信中,服務(wù)器的工作流程如下:(1)使用socket()方法創(chuàng)建socket對象;(2)使用bind()方法將服務(wù)器進程與端口地址綁定;(3)使用listen()方法開啟服務(wù)器監(jiān)聽;(4)使用accept()方法阻塞等待接受客戶端的連接請求;(4)當(dāng)有客戶端請求遞達時,使用recv()方法接收客戶端發(fā)送的請求數(shù)據(jù);(5)服務(wù)器處理接收到的數(shù)據(jù),并可能進行相應(yīng)的業(yè)務(wù)邏輯處理。(6)處理完成后使用send()方法向客戶端反饋應(yīng)答數(shù)據(jù)(響應(yīng)數(shù)據(jù))。(7)若仍有需求則繼續(xù)進行數(shù)據(jù)接收和反饋的操作,否則使用close()方法關(guān)閉socket對象。需要說明的是,由于服務(wù)器需要一直保持運行,所以通常情況下服務(wù)器不會關(guān)閉監(jiān)聽的socket。除非遇到特殊情況,例如需要停止服務(wù)器進行維護,才會關(guān)閉服務(wù)器監(jiān)聽的socket。1.面向連接的通信13.2.2socket通信流程在面向連接的通信中,客戶端的工作流程如下:(1)使用socket()方法創(chuàng)建socket對象;(2)使用connect()方法向服務(wù)端發(fā)起連接;(3)連接建立后,使用send()方法向服務(wù)器發(fā)送請求數(shù)據(jù);(4)使用recv()方法接收服務(wù)器返回的應(yīng)答數(shù)據(jù)(響應(yīng)數(shù)據(jù));(5)若仍有需求則繼續(xù)進行數(shù)據(jù)發(fā)送和接收的操作,否則使用close()方法關(guān)閉socket對象,并向服務(wù)器發(fā)送請求結(jié)束通知。2.面向非連接的通信13.2.2socket通信流程面向非連接的通信與生活中的郵件投遞類似。在郵件投遞中,接收郵件的一方無需一直等待發(fā)送郵件的一方發(fā)起連接請求,發(fā)送郵件的一方只需知道接收方的收件地址,便可直接投遞郵件。同樣,在面向非連接的通信中,接收方無需主動等待發(fā)送方的連接請求,發(fā)送方只需要知道接收方的地址,就可以直接發(fā)送數(shù)據(jù)。2.面向非連接的通信面向非連接的通信流程如圖所示。13.2.2socket通信流程面向非連接的通信流程與面向連接的通信流程大致相同,區(qū)別在于面向非連接的通信中,客戶端不再發(fā)起連接請求,而是使用sendto()方法向指定的服務(wù)器發(fā)送請求數(shù)據(jù);服務(wù)器則使用recvfrom()方法接收數(shù)據(jù),并使用sendto()方法將應(yīng)答數(shù)據(jù)(響應(yīng)數(shù)據(jù))反饋到客戶端。13.2.2socket通信流程2.面向非連接的通信
先定一個小目標(biāo)!掌握socket內(nèi)置方法,能夠通過這些方法實現(xiàn)socket通信13.2.3socket內(nèi)置方法常用內(nèi)置方法13.2.3socket內(nèi)置方法socket模塊為socket對象定義了一些內(nèi)置方法,通過這些內(nèi)置方法,可以實現(xiàn)socket通信,常用的方法如表所示。方法說明bind()將套接字與指定的通信地址綁定listen()將套接字變?yōu)楸O(jiān)聽套接字,并設(shè)置允許等待接受的最大連接數(shù)setblocking()設(shè)置套接字的阻塞狀態(tài),默認為True表示阻塞,F(xiàn)alse表示非阻塞connect()向指定地址發(fā)起連接請求accept()接受連接請求send()/sendto()發(fā)送數(shù)據(jù)/向指定地址的進程發(fā)送數(shù)據(jù)recv()/recvfrom()接收數(shù)據(jù)close()關(guān)閉套接字1.bind()方法13.2.3socket內(nèi)置方法確??蛻舳四軠?zhǔn)確地找到服務(wù)器,服務(wù)器的地址通常是固定的。在創(chuàng)建服務(wù)器的socket后,需要通過bind()方法將服務(wù)器的socket與服務(wù)器地址綁定,bind()方法的語法格式如下:bind(address)語法格式address:該參數(shù)是一個形如(hostname,port)的元組,元組中的第一個元素hostname是一個字符串,表示主機地址;第二個元素port是一個整數(shù),表示進程端口號。當(dāng)元組中的hostname為空字符串時,進程使用本機的任意IP地址作為主機地址。假設(shè)當(dāng)前服務(wù)器的socket為socket_server,主機名為“1”,端口號為“3456”,那么bind()的用法如下:socket_server.bind(('1',3546))示例13.2.3socket內(nèi)置方法1.bind()方法客戶端的socket也可以調(diào)用bind()方法綁定一個地址,但因為客戶端進程存活時間相對較短,且客戶端套接字為主動套接字,服務(wù)器在接收數(shù)據(jù)時動態(tài)地獲取客戶端地址已能滿足需求,所以客戶端一般不進行此項操作??蛻舳诉M程的端口號通常由系統(tǒng)隨機分配。2.listen()方法13.2.3socket內(nèi)置方法服務(wù)器的socket應(yīng)被動地監(jiān)聽客戶端的連接請求,但默認情況下套接字工作在主動狀態(tài),可主動發(fā)送數(shù)據(jù)。調(diào)用listen()方法將使一個套接字由主動狀態(tài)變?yōu)楸粍訝顟B(tài),以等待接收客戶端的連接請求。listen()方法的語法格式如下:listen([backlog])語法格式backlog:該參數(shù)用于指定在拒絕新連接之前,系統(tǒng)允許的未完成連接數(shù)。參數(shù)backlog是可選的,若指定該參數(shù),則它的值至少為0;若缺省該參數(shù),系統(tǒng)會選擇一個合理的默認值為其賦值。內(nèi)核為監(jiān)聽套接字維護了兩個隊列:已連接隊列和未連接隊列。完成三次握手過程的客戶端對應(yīng)的套接字將被添加到已連接隊列中,處于半連接狀態(tài)的客戶端對應(yīng)的套接字將被添加到未連接隊列中。若未連接隊列存滿,再有新的客戶端發(fā)起連接請求,該連接請求將被直接拒絕。socket_server.listen(5)示例13.2.3socket內(nèi)置方法2.listen()方法3.connect()方法13.2.3socket內(nèi)置方法connect()方法由客戶端的socket對象調(diào)用,該方法的功能是向服務(wù)器發(fā)起連接請求。connect()方法的語法格式如下:connect(address)語法格式address:該參數(shù)是一個形如(hostname,port)的元組,用于指定服務(wù)器的地址。若連接出錯,connect()方法將返回socket.error錯誤。假設(shè)客戶端的socket對象為client_socket,則connect()方法的用法如下所示:client_socket.connect(('1',3546))示例13.2.3socket內(nèi)置方法3.connect()方法4.accept()方法13.2.3socket內(nèi)置方法accept()方法由服務(wù)器的socket對象調(diào)用,該方法的功能是處理客戶端發(fā)起的連接請求。accept()方法的語法格式如下:accept()語法格式若調(diào)用accept()方法前沒有客戶端連接請求到達,accept()方法將會使服務(wù)器阻塞,直到有客戶端請求連接到達時才會返回;否則accept()方法立即返回一個形如(conn,address)的元組,元組中conn是新的套接字對象,用于與相應(yīng)客戶端進行數(shù)據(jù)交互,address是客戶端的地址,它的值是一個形如(hostname,port)的元組。client_socket,address=socket_server.accept()示例send()、sendto()方法用于向目標(biāo)進程發(fā)送數(shù)據(jù),它們的語法格式分別如下:13.2.3socket內(nèi)置方法5.send()/sendto()方法send(bytes[,
flags])sendto(bytes,
flags,
address)語法格式send()方法由流式套接字調(diào)用;sendto()方法一般由數(shù)據(jù)報式套接字調(diào)用。參數(shù)bytes用于設(shè)置要發(fā)送的字節(jié)流數(shù)據(jù),可以通過以下兩種方式傳遞字節(jié)流數(shù)據(jù):(1)以“b'string'”的形式傳入?yún)?shù),例如傳遞的字符串為“helloitheima”,則send()方法的用法為send(b'helloitheima'),這種方式只能轉(zhuǎn)換ASCII字符。(2)通過encode()方法對字符串進行轉(zhuǎn)碼,encode()方法中需傳入一個表示字節(jié)碼格式的參數(shù),比如將字符串轉(zhuǎn)為gb2312編碼的字節(jié)流數(shù)據(jù),則應(yīng)使用語句send('helloitheima'.encode('gb2312'))。參數(shù)flags用于指定發(fā)送數(shù)據(jù)的特殊選項,它支持以下幾個常用取值:socket.MSG_DONTWAIT:非阻塞發(fā)送。socket.MSG_OOB:發(fā)送帶外數(shù)據(jù)。socket.MSG_PEEK:僅查看而不移除接收緩沖區(qū)中的數(shù)據(jù)。socket.MSG_WAITALL:等待直到所有數(shù)據(jù)都被發(fā)送或接收完成。0:默認值,不對發(fā)送操作進行特殊處理。flags參數(shù)的值可能因操作系統(tǒng)的不同而有所差異。一般情況下可以不指定flags參數(shù),直接使用默認值0即可。13.2.3socket內(nèi)置方法5.send()/sendto()方法sendto()方法中的參數(shù)address本質(zhì)為一個形如(hostname,port)的元組,用于指定目標(biāo)進程的地址。send()、sendto()方法調(diào)用成功都會返回所發(fā)送數(shù)據(jù)的字節(jié)數(shù),它們的用法如下所示:send(b'helloworld')sendto(b'helloworld',('2',4567))示例13.2.3socket內(nèi)置方法5.send()/sendto()方法13.2.3socket內(nèi)置方法recv()、recvfrom()方法用于接收數(shù)據(jù),它們的語法格式分別如下:recv(bufsize[,
flags])recvfrom(bufsize[,
flags])語法格式6.recv()/recvfrom()方法bufsize:該參數(shù)用于設(shè)置可接收的最大數(shù)據(jù)量。若方法調(diào)用成功,返回接收到的數(shù)據(jù)。recvfrom()方法的參數(shù)bufsize同樣用于設(shè)置可接收的最大數(shù)據(jù)量。若該方法被調(diào)用成功,recvfrom()方法將返回一個形如(data,address)的元組,元組中data是接收到的數(shù)據(jù),address是發(fā)送數(shù)據(jù)的套接字地址。close()方法用于關(guān)閉套接字。類似于文件,套接字也是系統(tǒng)中的一種資源,使用完畢的套接字應(yīng)及時關(guān)閉。此外,一臺主機中端口的數(shù)量是有限的,系統(tǒng)同樣應(yīng)關(guān)閉空閑的套接字,避免端口浪費。client_socket.close()server_socket.close()示例13.2.3socket內(nèi)置方法7.close()方法當(dāng)客戶端終止后,服務(wù)器中與此客戶端交互的套接字也應(yīng)關(guān)閉。一般情況下,若套接字接收到的數(shù)據(jù)為空,則說明客戶端進程已經(jīng)關(guān)閉連接,因此可通過判斷接收到的數(shù)據(jù)長度判斷是否關(guān)閉與客戶端交互的套接字。
先定一個小目標(biāo)!根據(jù)任務(wù)分析實現(xiàn)實例1:掃描開放端口13.2.4實例1:掃描開放端口用戶可根據(jù)“IP地址:端口號”訪問網(wǎng)絡(luò)中計算機的進程,不過難免有些別有用心之人利用此方式進行惡意訪問。為避免其他人侵入計算機,運維人員通常會采取關(guān)閉冗余端口的措施進行預(yù)防,但計算機中擁有的端口數(shù)量較多,僅靠人力排查的方式顯然是不可取的。因此,考慮通過編程解決這一問題。本實例要求編寫程序,掃描計算機端口,輸出開放的端口號。13.2.4實例1:掃描開放端口使用列表保存價格信息。定義空列表用于保存用戶選購商品的價格。接收輸入的最大價格和最小價格。從價格列表中獲取每個商品價格。判斷商品價格區(qū)間。將商品價格進行排序。實現(xiàn)思路13.2.4實例1:掃描開放端口在Chapter13項目中創(chuàng)建01_sacn.py文件。在01_sacn.py中編寫代碼。運行01_sacn.py文件。實現(xiàn)步驟13.2.4實例1:掃描開放端口基于UDP的網(wǎng)絡(luò)聊天室13.3
先定一個小目標(biāo)!掌握基于UDP的網(wǎng)絡(luò)聊天室功能,能夠?qū)崿F(xiàn)基于UDP的網(wǎng)絡(luò)聊天室13.3基于UDP的網(wǎng)絡(luò)聊天室基于UDP的網(wǎng)絡(luò)聊天室13.3基于UDP的網(wǎng)絡(luò)聊天室defmain():
server_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#創(chuàng)建服務(wù)器的socket
server_socket.bind(("",3456))
#綁定地址
print("-------UDP聊天室-------")
#接收數(shù)據(jù)并輸出
whileTrue:
recv_info=server_socket.recvfrom(1024)
address=recv_info[1][0]+':'+str(recv_info[1][1])
print("%s"%address)
print("%s"%recv_info[0].decode("gb2312"))
server_socket.close()#關(guān)閉服務(wù)器的socket示例聊天窗口是一個基于UDP協(xié)議的服務(wù)器,編輯框則是一個基于UDP協(xié)議的客戶端。聊天窗口應(yīng)可接收編輯框發(fā)送來的數(shù)據(jù),并將發(fā)送數(shù)據(jù)的地址以及數(shù)據(jù)顯示到聊天室中。基于UDP的網(wǎng)絡(luò)聊天室13.3基于UDP的網(wǎng)絡(luò)聊天室defmain():
client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#創(chuàng)建客戶端的socket
print('----輸入框----')
#向服務(wù)器發(fā)送數(shù)據(jù)
whileTrue:
data=input()
client_socket.sendto(data.encode("gb2312"),("1",3456))
ifdata=='88':
break
client_socket.close()
#關(guān)閉客戶端的socket示例為測試服務(wù)器接收與處理客戶端數(shù)據(jù)的功能,下面實現(xiàn)一個消息編輯發(fā)送功能的客戶端??蛻舳说木唧w實現(xiàn)如下:基于UDP的網(wǎng)絡(luò)聊天室13.3基于UDP的網(wǎng)絡(luò)聊天室需要說明的是,在多臺計算機中進行測試時,計算機中的防火墻可能會過濾掉來自其他主機的UDP客戶端發(fā)送的數(shù)據(jù)包,為保證測試成功,可先使用“serviceiptablesstop”命令關(guān)閉防火墻,測試完成后,再通過“serviceiptablesstart”命令重啟防火墻?;赥CP的數(shù)據(jù)轉(zhuǎn)換13.4
先定一個小目標(biāo)!掌握基于TCP的數(shù)據(jù)轉(zhuǎn)換功能,能夠?qū)崿F(xiàn)基于TCP的數(shù)據(jù)轉(zhuǎn)換13.4基于TCP的數(shù)據(jù)轉(zhuǎn)換基于TCP的數(shù)據(jù)轉(zhuǎn)換13.4基于TCP的數(shù)據(jù)轉(zhuǎn)換基于TCP的數(shù)據(jù)轉(zhuǎn)換是一種可靠的數(shù)據(jù)傳輸方式。在這種轉(zhuǎn)換中,數(shù)據(jù)被分割成小的數(shù)據(jù)包,并按照順序一個一個地通過TCP連接進行發(fā)送和接收,以確保數(shù)據(jù)的完整性和順序性。當(dāng)基于TCP實現(xiàn)數(shù)據(jù)轉(zhuǎn)換的功能時,數(shù)據(jù)轉(zhuǎn)換程序一般位于服務(wù)器端,它可以接收客戶端發(fā)送的數(shù)據(jù),將這些數(shù)據(jù)進行相應(yīng)的轉(zhuǎn)換操作后返回給客戶端。比如,服務(wù)器端接收用戶發(fā)送的字符,將這些字符轉(zhuǎn)換為大寫形式后返回給客戶端,具體如圖所示。13.4基于TCP的數(shù)據(jù)轉(zhuǎn)換基于TCP的數(shù)據(jù)轉(zhuǎn)換實現(xiàn)基于TCP的數(shù)據(jù)轉(zhuǎn)換程序,用于將客戶端發(fā)送的字符轉(zhuǎn)換為大寫形式的,具體代碼如下:defmain():server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創(chuàng)建套接字server_socketserver_socket.bind(("",5678))#綁定地址server_socket.listen(5)#設(shè)置最大連接數(shù)client_socket,address=server_socket.accept()#創(chuàng)建連接print('-----TCP數(shù)據(jù)轉(zhuǎn)換器-----')whileTrue:#接收數(shù)據(jù)recv_info=client_socket.recv(1024).decode('gb2312')string_address=address[0]+':'+str(address[1])13.4基于TCP的數(shù)據(jù)轉(zhuǎn)換基于TCP的數(shù)據(jù)轉(zhuǎn)換實現(xiàn)基于TCP的數(shù)據(jù)轉(zhuǎn)換程序,用于將客戶端發(fā)送的字符轉(zhuǎn)換為大寫形式的,具體代碼如下:print(string_address)print("待處理數(shù)據(jù):%s"%recv_info)ifrecv_info:#數(shù)據(jù)處理data=recv_info.upper()client_socket.send(data.encode('gb2312'))print("處理結(jié)果:%s"%data)else:print('exit')client_socket.close()breakserver_socket.close()#關(guān)閉套接字server_socket12.4線程的概念線程的概念為測試該程序的功能,下面實現(xiàn)一個用于發(fā)送數(shù)據(jù)和接收數(shù)據(jù)處理結(jié)果的客戶端程序,客戶端程序代碼如下。defmain():client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創(chuàng)建套接字client_socketclient_socket.connect(('1',5678))#請求連接#發(fā)送數(shù)據(jù)whileTrue:data=input("-----待處理數(shù)據(jù)------\n")client_socket.send(data.encode('gb2312'))recv_info=client_socket.recv(1024).decode('gb2312')print("------處理結(jié)果-------\n%s"%recv_info)#關(guān)閉套接字client_socketclient_socket.close()多學(xué)一招:端口保留端口保留服務(wù)器在網(wǎng)絡(luò)中的地址是唯一的,因此在為其設(shè)置端口號時,必須使用主機中的空閑端口號。但有時使用的是空閑端口號,卻還是會遇到如下所示的問題:OSError:[WinError10048]通常每個套接字地址(協(xié)議/網(wǎng)絡(luò)地址/端口)只允許使用一次。之所以出現(xiàn)上述問題,這是因為默認情況下內(nèi)核會在進程終止的兩分鐘內(nèi)保留進程的端口號。若想解決這一問題,可以在創(chuàng)建套接字后,執(zhí)行如下語句:server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)調(diào)用的方法setsockopt()用于設(shè)置套接字的選項,當(dāng)其中的第三個參數(shù)被設(shè)置為1時,服務(wù)器終止后在兩分鐘內(nèi)重新啟動可重復(fù)使用同一個端口。實例2:TCP文件下載13.5
先定一個小目標(biāo)!掌握線程的創(chuàng)建與啟動,能夠通過threading模塊的Thread類或子類創(chuàng)建線程13.5實例2:TCP文件下載文件下載是指客戶端將文件從服務(wù)器拷貝到本地。下載文件時,服務(wù)器將根據(jù)客戶端輸入的文件名到指定的目錄中查找,若找到了相應(yīng)的文件,服務(wù)器會讀取文件,將讀取的內(nèi)容發(fā)送到客戶端;客戶端接收服務(wù)器發(fā)送的數(shù)據(jù),提示用戶選擇下載的位置,并將接收到的數(shù)據(jù)寫入到目標(biāo)位置。本實例要求編寫程序,實現(xiàn)基于TCP的文件下載功能。13.5實例2:TCP文件下載使用列表保存價格信息。定義空列表用于保存用戶選購商品的價格。接收輸入的最大價格和最小價格。從價格列表中獲取每個商品價格。判斷商品價格區(qū)間。將商品價格進行排序。實現(xiàn)思路13.5實例2:TCP文件下載在Chapter13項目中創(chuàng)建tcp_download.py文件。在tcp_download.py中編寫代碼。運行tcp_download.py文件。實現(xiàn)步驟13.5實例2:TCP文件下載TCP并發(fā)服務(wù)器13.6
先定一個小目標(biāo)!掌握并發(fā)服務(wù)器,能夠?qū)崿F(xiàn)單進程非阻塞服務(wù)器13.6.1單進程非阻塞服務(wù)器單進程非阻塞服務(wù)器單進程非阻塞服務(wù)器通過解阻塞的方式實現(xiàn)并發(fā)操作。Python中套接字默認以阻塞方式處理數(shù)據(jù),若套接字調(diào)用accept()、recv()等方法時沒有接收到數(shù)據(jù),套接字就會阻塞等待數(shù)據(jù)遞達。用戶可通過套接字中提供的setblocking()方法將套接字設(shè)置為非阻塞模式,如此即便套接字中沒有數(shù)據(jù)遞達,套接字調(diào)用的方法也會立刻返回。13.6.1單進程非阻塞服務(wù)器setblocking()的使用示例如下:13.6.1單進程非阻塞服務(wù)器單進程非阻塞服務(wù)器server_socket.setblocking(False)示例setblocking()方法中參數(shù)的默認值為True,表示套接字默認工作在阻塞模式。以上示例中的參數(shù)的值為False,用于將套接字設(shè)置為非阻塞模式。若要使服務(wù)器可以與多個客戶端建立連接,需要保證在調(diào)用accept()方法時不會產(chǎn)生阻塞,即服務(wù)器套接字server_socket應(yīng)被設(shè)置為非阻塞;若要使每個連接中的客戶端都可隨時向服務(wù)器中發(fā)送數(shù)據(jù),則需保證在調(diào)用recv()方法時不產(chǎn)生阻塞,即新套接字new_socket應(yīng)被設(shè)置為非阻塞。
先定一個小目標(biāo)!掌握并發(fā)服務(wù)器,能夠?qū)崿F(xiàn)多進程并發(fā)服務(wù)器13.6.2多進程并發(fā)服務(wù)器多進程并發(fā)服務(wù)器多進程并發(fā)服務(wù)器中的主進程用于處理客戶端的連接請求,當(dāng)有新的客戶端與服務(wù)器建立連接后,服務(wù)器會創(chuàng)建一個子進程,由子進程完成數(shù)據(jù)的交互工作。13.6.2多進程并發(fā)服務(wù)器線程鎖概述13.6.2多進程并發(fā)服務(wù)器以將小寫字符串轉(zhuǎn)為大寫字符串的服務(wù)器為例,實現(xiàn)多進程并發(fā)服務(wù)器。importsocket,multiprocessingdefdeal_with_client(new_socket,client_address):whileTrue:recv_data=new_socket.recv(1024).decode('gb2312')iflen(recv_data)>0:print('待處理數(shù)據(jù):%s:%s'%(str(client_address),recv_data))data=recv_data.upper()new_socket.send(data.encode('gb2312'))else:print('客戶端[%s]已關(guān)閉'%str(client_address))breaknew_socket.close()線程鎖概述13.6.2多進程并發(fā)服務(wù)器以將小寫字符串轉(zhuǎn)為大寫字符串的服務(wù)器為例,實現(xiàn)多進程并發(fā)服務(wù)器。defmain():server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創(chuàng)建服務(wù)器套接字server_socketserver_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#端口快速重啟用local_address=('',8081)server_socket.bind(local_address)server_socket.listen(5)print('-----服務(wù)器------')
續(xù)...線程鎖概述13.6.2多進程并發(fā)服務(wù)器以將小寫字符串轉(zhuǎn)為大寫字符串的服務(wù)器為例,實現(xiàn)多進程并發(fā)服務(wù)器。
續(xù)...try:whileTrue:#處理客戶端連接請求new_socket,client_address=server_socket.accept()print('一個新的客戶端到達[%s]'%str(client_address))#創(chuàng)建子進程與客戶端進行交互client=multiprocessing.Process(target=deal_with_client,rgs=(new_socket,client_address))client.start()new_socket.close()#關(guān)閉父進程中的套接字new_socketfinally:server_socket.close()#關(guān)閉服務(wù)器套接字線程鎖概述13.6.2多進程并發(fā)服務(wù)器為測試此段服務(wù)器代碼,這里實現(xiàn)一個可向服務(wù)器發(fā)送數(shù)據(jù),并接收服務(wù)器反饋數(shù)據(jù)的客戶端。客戶端的代碼實現(xiàn)如下:importsocketdefmain():client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創(chuàng)建套接字client_socketclient_socket.connect(('1',8081))#請求連接whileTrue:#發(fā)送數(shù)據(jù)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年華東師大版九年級生物上冊月考試卷含答案
- 2025年北師大新版選修4地理下冊月考試卷含答案
- 二零二五版拌合料行業(yè)技術(shù)交流與合作開發(fā)合同4篇
- 二零二五年度陶瓷面磚研發(fā)及采購合同4篇
- 二零二五版美團外賣外賣配送高峰期應(yīng)急預(yù)案合同4篇
- 2025年新型共享辦公空間租賃合同3篇
- 掛鉤生產(chǎn)單位的合同(2篇)
- 2025年度木門安裝工程招標(biāo)合同4篇
- 2025年度門窗安裝工程設(shè)計與施工一體化合同4篇
- 2025年度民間借貸融資租賃與資產(chǎn)證券化合同4篇
- 射頻在疼痛治療中的應(yīng)用
- 和平精英電競賽事
- 四年級數(shù)學(xué)豎式計算100道文檔
- “新零售”模式下生鮮電商的營銷策略研究-以盒馬鮮生為例
- 項痹病辨證施護
- 職業(yè)安全健康工作總結(jié)(2篇)
- 懷化市數(shù)字經(jīng)濟產(chǎn)業(yè)發(fā)展概況及未來投資可行性研究報告
- 07FD02 防空地下室電氣設(shè)備安裝
- 教師高中化學(xué)大單元教學(xué)培訓(xùn)心得體會
- 彈簧分離問題經(jīng)典題目
- 部編版高中歷史中外歷史綱要(下)世界史導(dǎo)言課課件
評論
0/150
提交評論