第十四章 網絡編程

第十四章 網絡編程

本章首先概述Python標準庫中的一些網絡模塊。然后討論SocketServer和相關的類,并介紹同時處理多個連接的各種方法。最后,簡單地說一說Twisted,這是一個使用Python編寫網絡程序的框架,功能豐富而成熟。

幾個網絡模塊

模塊socket

網絡編程中的一個基本組件是套接字(socket)。
套接字基本上是一個信息通道,兩端各有一個程序。
套接字分為兩類:服務器套接字和客戶端套接字。

為傳輸數據,套接字提供了兩個方法:send和recv(表示receive)。
要發送數據,可調用方法send并提供一個字符串;
要接收數據,可調用recv并指定最多接收多少個字節的數據。

最簡單的服務器
服務器套接字先調用方法bind,再調用方法listen來監聽特定的地址。
然后,客戶端套接字就可連接到服務器了,辦法是調用方法connect并提供調用方法bind時指定的地址(在服務器端,可使用函數socket.gethostname獲取當前機器的主機名)。這里的地址是一個格式為(host, port)的元組,其中host是主機名(如www.example.com),而port是端口號(一個整數)。
方法listen接受一個參數——待辦任務清單的長度(即最多可有多少個連接在隊列中等待接納,到達這個數量后將開始拒絕連接)
服務器套接字開始監聽后,就可接受客戶端連接了,這是使用方法accept來完成的。這個方法將阻斷(等待)到客戶端連接到來為止,然后返回一個格式為(client, address)的元組,其中client是一個客戶端套接字,而address是前面解釋過的地址。服務器能以其認為合適的方式處理客戶端連接,然后再次調用accept以接著等待新連接到來。這通常是在一個無限循環中完成的。

import socket
s = socket.socket()host = socket.gethostname()
port = 1234
s.bind((host,port))s.listen(5)
while True:c,addr = s.accept()print('Got connection from',addr)c.send('Thank you for connecting')c.close()

最簡單的客戶端

import socket
s = socket.socket()host = socket.gethostname()
port = 1234s.connect((host,port))
print(s.recv(1024))

模塊urllib和urllib2

1,打開遠程文件

from urllib.request import urlopen
import rewebpage = urlopen('https://beyondyanyu.blog.csdn.net')#變量webpage將包含一個類似于文件的對象,這個對象與該網站相關聯
text = webpage.read()
m = re.search(b'<a href="([^"]+)".*?>about</a>',text,re.IGNORECASE)
m.group(1)

2,獲取遠程文件
函數urlopen返回一個類似于文件的對象,可從中讀取數據。
可使用urlretrieve,下載文件,并將其副本存儲在一個本地文件中。
這個函數不返回一個類似于文件的對象,而返回一個格式為(filename, headers)的元組,其中filename是本地文件的名稱(由urllib自動創建),而headers包含一些有關遠程文件的信息。
調用函數urlcleanup且不提供任何參數,清空所有臨時文件。

獲取CSDN的主頁,并將其存儲到文件C:\webpage.html中。

urlretrieve('https://beyondyanyu.blog.csdn.net', 'C:\\python_webpage.html')

一些實用的函數

函數名稱描述
quote(string[, safe])返回一個字符串,其中所有的特殊字符(在URL中有特殊意義的字符)都已替換為對URL友好的版本(如將~替換為%7E)參數safe是一個字符串(默認為’/’),包含不應像這樣對其進行編碼的字符。
quote_plus(string[, safe])類似于quote,但也將空格替換為加號。
unquote(string)與quote相反。
unquote_plus(string)與quote_plus相反。
urlencode(query[, doseq])將映射(如字典)或由包含兩個元素的元組(形如(key,value))組成的序列轉換為“使用URL編碼的”字符串。

其他模塊

模塊描述
asynchat包含補充asyncore的功能
asyncore異步套接字處理程序
cgi基本的CGI支持
CookieCookie對象操作,主要用于服務器
cookielib客戶端Cookie支持
email電子郵件(包括MIME)支持
ftplibFTP客戶端模塊
gopherlibGopher客戶端模塊
httplibHTTP 客戶端模塊
imaplibIMAP4客戶端模塊
mailbox讀取多種郵箱格式
mailcap通過mailcap文件訪問MIME配置
mhlib訪問MH郵箱
nntplibNNTP客戶端模塊
poplibPOP客戶端模塊
robotparser解析Web服務器robot文件
SimpleXMLRPCServer一個簡單的XML-RPC服務器
smtpdSMTP服務器模塊
smtplibSMTP客戶端模塊
telnetlibTelnet客戶端模塊
urlparse用于解讀URL
xmlrpclibXML-RPC客戶端支持

SocketServer及相關的類

模塊SocketServer是標準庫提供的服務器框架的基石,這個框架包括BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer和DocXMLRPCServer等服務器,它們在基本服務器的基礎上添加了各種功能。

SocketServer包含4個基本的服務器:TCPServer(支持TCP套接字流)、UDPServer(支持UDP數據報套接字)以及更難懂的UnixStreamServer和UnixDatagramServer。后面3個你可能不會用到。

使用模塊SocketServer編寫服務器時,大部分代碼都位于請求處理器中。
基本請求處理程序類BaseRequestHandler將所有操作都放在一個方法中——服務器調用的方法handle。這個方法可通過屬性self.request來訪問客戶端套接字。
如果處理的是流(使用TCPServer時很可能如此),可使用StreamRequestHandler類,它包含另外兩個屬性:self.rfile(用于讀取)和self.wfile(用于寫入)。

基于SocketServer的極簡服務器

from socketserver import TCPServer,StreamRequestHandlerclass Handler(StreamRequestHandler):def handle(self):addr = self.request.getpeername()print('Got connection from',addr)self.wfile.write('Thank you for connecting')server = TCPServer(('',1234),Handler)
server.serve_forever()

多個連接

處理多個連接的主要方式有三種:分叉(forking)、線程化異步I/O
分叉占用的資源較多,且在客戶端很多時可伸縮性不佳。

進程:運行著的程序
分叉:對進程(運行的程序)進行分叉時,基本上是復制它,而這樣得到的兩個進程都將從當前位置開始繼續往下執行,且每個進程都有自己的內存副本(變量等)。原來的進程為父進程,復制的進程為子進程。查看函數fork的返回值可以區別父子進程。

在分叉服務器中,對于每個客戶端連接,都將通過分叉創建一個子進程。父進程繼續監聽新連接,而子進程負責處理客戶端請求。客戶端請求結束后,子進程直接退出。由于分叉出來的進程并行地運行,因此客戶端無需等待。

鑒于分叉占用的資源較多(每個分叉出來的進程都必須有自己的內存),還有另一種解決方案:線程化

線程是輕量級進程(子進程),都位于同一個進程中并共享內存。
這減少了占用的資源,但也帶來了一個缺點:由于線程共享內存,你必須確保它們不會彼此干擾或同時修改同一項數據,否則將引起混亂。這些問題都屬于同步問題。

種避免線程和分叉的辦法是使用Stackless Python。它是一個能夠快速而輕松地在不同上下文之間切換的Python版本。它支持一種類似于線程的并行方式,名為微線程,其可伸縮性比真正的線程高得多。

使用SocketServer實現分叉和線程化

僅當方法handle需要很長時間才能執行完畢時,分叉和線程化才能提供幫助。請注意,Windows不支持分叉

分叉服務器

from socketserver import TCPSercer,ForkingMixIn,StreamRequestHandler
class Server(ForkingMixIn,TCPSercer):pass
class Handler(StreamRequestHandler):def handle(self):addr = self.request.getpeername()print('Got connection from',addr)self.wfile.write('Thank you for connecting')server = Server(('',1234),Handler)
server.serve_forever()

線程化服務器

from socketserver import TCPServer, ThreadingMixIn, StreamRequestHandler
class Server(ThreadingMixIn, TCPServer): pass
class Handler(StreamRequestHandler):def handle(self):addr = self.request.getpeername()print('Got connection from', addr)self.wfile.write('Thank you for connecting')server = Server(('', 1234), Handler)
server.serve_forever()

使用select和poll實現異步I/O

當服務器與客戶端通信時,來自客戶端的數據可能時斷時續。如果使用了分叉和線程化,這就不是問題:因為一個進程(線程)等待數據時,其他進程(線程)可繼續處理其客戶端。
然而,另一種做法是只處理當前正在通信的客戶端。你甚至無需不斷監聽,只需監聽后將客戶端加入隊列即可。這就是框架asyncore/asynchat和Twisted采取的方法。
這種功能的基石是函數select或poll)。這兩個函數都位于模塊select中,其中poll的可伸縮性更高,但只有UNIX系統支持它(Windows不支持)。

使用select的簡單服務器
函數select接受三個必不可少的參數和一個可選參數,其中前三個參數為序列,而第四個參數為超時時間(單位為秒)。這三個序列分別表示需要輸入和輸出以及發生異常(錯誤等)的連接。
如果沒有指定超時時間,select將阻斷(即等待)到有文件描述符準備就緒;
如果指定了超時時間,select將最多阻斷指定的秒數;
如果超時時間為零,select將不斷輪詢(即不阻斷)。

select返回三個序列(即一個長度為3的元組),其中每個序列都包含相應參數中處于活動狀態的文件描述符。

import socket,select
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host,port))
s.listen(5)
inputs = [s]
while True:rs,ws,es = select.select(inputs,[],[])for r in rs:if r is s:c,addr = s.accept()print('Got connection from',addr)inputs.append(c)else:try:data = r.recv(1024)disconnected = not dataexcept socket.error:disconnected = Trueif disconnected:print(r.getpeername(),'disconnected')inputs.remove(r)else:print(data)

select模塊中的輪詢事件常量

事件名描述
POLLIN文件描述符中有需要讀取的數據
POLLPRI文件描述符中有需要讀取的緊急數據
POLLOUT文件描述符為寫入數據做好了準備
POLLERR文件描述符出現了錯誤狀態
POLLHUP掛起。連接已斷開。
POLLNVAL無效請求。連接未打開

使用poll的簡單服務器
方法poll使用起來比select容易。調用poll時,將返回一個輪詢對象。
使用方法register向這個對象注冊文件描述符(或包含方法fileno的對象)。
注冊后可使用方法unregister將它們刪除。注冊對象(如套接字)后,可調用其方法poll(它接受一個可選的超時時間參數)。
這將返回一個包含(fd, event)元組的列表(可能為空),其中fd為文件描述符,而event是發生的事件。event是一個位掩碼,這意味著它是一個整數,其各個位對應于不同的事件。

import socket,selects = socket.socket()host = socket.gethostname()
port = 1234
s.bind((host,port))fdmap = {s.fileno():s}s.listen(5)
p = select.poll()
p.register(s)
while True:events = p.poll()for fd, event in events:if fd in fdmap:c, addr = s.accept()print('Got connection from', addr)p.register(c)fdmap[c.fileno()] = celif event & select.POLLIN:data = fdmap[fd].recv(1024)if not data: # 沒有數據 --連接已關閉print(fdmap[fd].getpeername(), 'disconnected')p.unregister(fd)del fdmap[fd]else:print(data)

Twisted

Twisted是由Twisted Matrix Laboratories(http://twistedmatrix.com)開發的,這是一個事件驅動的Python網絡框架。

使用Twisted創建的簡單服務器
事件處理程序是在協議中定義的。
你還需要一個工廠,它能夠在新連接到來時創建這樣的協議對象。
如果你只想創建自定義協議類的實例,可使用Twisted自帶的工廠——模塊twisted.internet.protocol中 的Factory類。
編寫自定義協議時,將模塊twisted.internet.protocol中的Protocol作為超類。
有新連接到來時,將調用事件處理程序connectionMade;
連接中斷時,將調用connectionLost。
來自客戶端的數據是通過處理程序dataReceived接收的。

from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factoryclass SimpleLogger(Protocol):def connectionMade(self):print('Got connection from', self.transport.client)def connectionLost(self, reason):print(self.transport.client, 'disconnected')def dataReceived(self, data):print(data)factory = Factory()
factory.protocol = SimpleLoggerreactor.listenTCP(1234, factory)
reactor.run()

使用協議LineReceiver改進后的日志服務器
如果使用telnet連接到這個服務器以便測試它,每行輸出可能只有一個字符,是否如此取決于緩沖等因素。
為此,可編寫一個自定義協議。模塊twisted.protocols.basic包含幾個預定義的協議,其中一個就是LineReceiver。
它實現了dataReceived,并在每收到一整行后調用事件處理程序lineReceived。

from twisted.internet import reactor 
from twisted.internet.protocol import Factory 
from twisted.protocols.basic import LineReceiverclass SimpleLogger(LineReceiver):def connectionMade(self): print('Got connection from', self.transport.client)def connectionLost(self, reason): print(self.transport.client, 'disconnected')def lineReceived(self, line): print(line)factory = Factory() 
factory.protocol = SimpleLogger 
reactor.listenTCP(1234, factory) 
reactor.run()

小結

概念描述
套接字和模塊socket套接字是讓程序(進程)能夠通信的信息通道,這種通信可能需要通過網絡進行。模塊socket讓你能夠在較低的層面訪問客戶端套接字和服務器套接字。服務器套接字在指定的地址處監聽客戶端連接,而客戶端套接字直接連接到服務器。
urllib和urllib2這些模塊讓你能夠從各種服務器讀取和下載數據,為此你只需提供指向數據源的URL即可。模塊urllib是一種比較簡單的實現,而urllib2功能強大、可擴展性極強。這兩個模塊都通過諸如urlopen等函數來完成工作。
框架SocketServer這個框架位于標準庫中,包含一系列同步服務器基類,讓你能夠輕松地編寫服務器。它還支持使用CGI的簡單Web(HTTP)服務器。如果要同時處理多個連接,必須使用支持分叉或線程化的混合類。
select和poll這兩個函數讓你能夠在一組連接中找出為讀取和寫入準備就緒的連接。這意味著你能夠以循環的方式依次為多個連接提供服務,從而營造出同時處理多個連接的假象。另外,相比于線程化或分叉,雖然使用這兩個函數編寫的代碼要復雜些,但解決方案的可伸縮性和效率要高得多。
Twisted這是Twisted Matrix Laboratories開發的一個框架,功能豐富而復雜,支持大多數主要的網絡協議。雖然這個框架很大且其中使用的一些成例看起來宛如天書,但其基本用法簡單而直觀。框架Twisted也是異步的,因此效率和可伸縮性都非常高。對很多自定義網絡應用程序來說,使用Twisted來開發很可能是最佳的選擇。

本章介紹的新函數

函數描述
urllib.urlopen(url[, data[, proxies]])根據指定的URL打開一個類似于文件的對象
urllib.urlretrieve(url[,fname[,hook[,data]]])下載URL指定的文件
urllib.quote(string[, safe])替換特殊的URL字符
urllib.quote_plus(string[, safe])與quote一樣,但也將空格替換為+
urllib.unquote(string)與quote相反
urllib.unquote_plus(string)與quote_plus相反
urllib.urlencode(query[, doseq])對映射進行編碼,以便用于CGI查詢中
select.select(iseq, oseq, eseq[, timeout])找出為讀/寫做好了準備的套接字
select.poll()創建一個輪詢對象,用于輪詢套接字
reactor.listenTCP(port, factory)監聽連接的Twisted函數
reactor.run()啟動主服務器循環的Twisted函數

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/378282.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/378282.shtml
英文地址,請注明出處:http://en.pswp.cn/news/378282.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言輸出11258循環,c/c++內存機制(一)(轉)

一&#xff1a;C語言中的內存機制在C語言中&#xff0c;內存主要分為如下5個存儲區&#xff1a;(1)棧(Stack)&#xff1a;位于函數內的局部變量(包括函數實參)&#xff0c;由編譯器負責分配釋放&#xff0c;函數結束&#xff0c;棧變量失效。(2)堆(Heap)&#xff1a;由程序員用…

【神經網絡八股擴展】:數據增強

課程來源&#xff1a;人工智能實踐:Tensorflow筆記2 文章目錄前言TensorFlow2數據增強函數數據增強網絡八股代碼&#xff1a;總結前言 本講目標:數據增強&#xff0c;增大數據量 關于我們為何要使用數據增強以及常用的幾種數據增強的手法&#xff0c;可以看看下面的文章&#…

C++:從C繼承的標準庫

C從C繼承了的標準庫 &#xff0c; 這就意味著 C 中 可以使用的標準庫函數 在C 中都可以使用 &#xff0c; 但是需要注意的是 &#xff0c; 這些標準庫函數在C中不再以 <xxx.h> 命名 &#xff0c; 而是變成了 <cxxx> 。 例如 &#xff1a; 在C中操作字符串的…

分享WCF聊天程序--WCFChat

無意中在一個國外的站點下到了一個利用WCF實現聊天的程序&#xff0c;作者是&#xff1a;Nikola Paljetak。研究了一下&#xff0c;自己做了測試和部分修改&#xff0c;感覺還不錯&#xff0c;分享給大家。先來看下運行效果&#xff1a;開啟服務&#xff1a;客戶端程序&#xf…

c# uri.host_C#| 具有示例的Uri.Equality()運算符

c# uri.hostUri.Equality()運算符 (Uri.Equality() Operator) Uri.Equality() Operator is overloaded which is used to compare two Uri objects. It returns true if two Uri objects contain the same Uri otherwise it returns false. Uri.Equality()運算符已重載&#xf…

第六章至第九章的單元測試

1,?助劑與纖維作用力大于纖維分子之間的作用力,則該助劑最好用作() 纖維增塑膨化劑。 2,助劑擴散速率快,優先占領纖維上的染座,但助劑與纖維之間作用力小于染料與纖維之間作用力,該助劑可以作為() 勻染劑。 3,助劑占領纖維上的染座,但助劑與纖維之間作用力大于染…

【神經網絡擴展】:斷點續訓和參數提取

課程來源&#xff1a;人工智能實踐:Tensorflow筆記2 文章目錄前言斷點續訓主要步驟參數提取主要步驟總結前言 本講目標:斷點續訓&#xff0c;存取最優模型&#xff1b;保存可訓練參數至文本 斷點續訓主要步驟 讀取模型&#xff1a; 先定義出存放模型的路徑和文件名&#xff0…

開發DBA(APPLICATION DBA)的重要性

開發DBA是干什么的&#xff1f; 1. 審核開發人員寫的SQL&#xff0c;并且糾正存在性能問題的SQL ---非常重要 2. 編寫復雜業務邏輯SQL&#xff0c;因為復雜業務邏輯SQL開發人員寫出的SQL基本上都是有性能問題的&#xff0c;與其讓開發人員寫&#xff0c;不如DBA自己寫。---非常…

javascript和var之間的區別?

You can define your variables in JavaScript using two keywords - the let keyword and the var keyword. The var keyword is the oldest way of defining and declaring variables in JavaScript whereas the let is fairly new and was introduced by ES15. 您可以使用兩…

小米手環6NFC安裝太空人表盤

以前看我室友峰哥、班長都有手環&#xff0c;一直想買個手環&#xff0c;不舍得&#xff0c;然后今年除夕的時候降價&#xff0c;一狠心&#xff0c;入手了&#xff0c;配上除夕的打年獸活動還有看春晚京東敲鼓領的紅包和這幾年攢下來的京東豆豆&#xff0c;原價279的小米手環6…

計算機二級c語言題庫縮印,計算機二級C語言上機題庫(可縮印做考試小抄資料)...

小抄,答案,形成性考核冊,形成性考核冊答案,參考答案,小抄資料,考試資料,考試筆記第一套1.程序填空程序通過定義學生結構體數組&#xff0c;存儲了若干個學生的學號、姓名和三門課的成績。函數fun 的功能是將存放學生數據的結構體數組&#xff0c;按照姓名的字典序(從小到大排序…

為什么兩層3*3卷積核效果比1層5*5卷積核效果要好?

目錄1、感受野2、2層3 * 3卷積與1層5 * 5卷積3、2層3 * 3卷積與1層5 * 5卷積的計算量比較4、2層3 * 3卷積與1層5 * 5卷積的非線性比較5、2層3 * 3卷積與1層5 * 5卷積的參數量比較1、感受野 感受野&#xff1a;卷積神經網絡各輸出特征像素點&#xff0c;在原始圖片映射區域大小。…

算法正確性和復雜度分析

算法正確性——循環不變式 算法復雜度的計算 方法一 代換法 —局部代換 這里直接對n變量進行代換 —替換成對數或者指數的情形 n 2^m —整體代換 這里直接對遞推項進行代換 —替換成內部遞推下標的形式 T(2^n) S(n) 方法二 遞歸樹法 —用實例說明 —分析每一層的內容 —除了…

第十五章 Python和Web

第十五章 Python和Web 本章討論Python Web編程的一些方面。 三個重要的主題&#xff1a;屏幕抓取、CGI和mod_python。 屏幕抓取 屏幕抓取是通過程序下載網頁并從中提取信息的過程。 下載數據并對其進行分析。 從Python Job Board&#xff08;http://python.org/jobs&#x…

array_chunk_PHP array_chunk()函數與示例

array_chunkPHP array_chunk()函數 (PHP array_chunk() Function) array_chunk() function is an array function, it is used to split a given array in number of array (chunks of arrays). array_chunk()函數是一個數組函數&#xff0c;用于將給定數組拆分為多個數組(數組…

raise

raise - Change a windows position in the stacking order button .b -text "Hi there!"pack [frame .f -background blue]pack [label .f.l1 -text "This is above"]pack .b -in .fpack [label .f.l2 -text "This is below"]raise .b轉載于:ht…

c語言輸出最大素數,for語句計算輸出10000以內最大素數怎么搞最簡單??各位大神們...

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include int* pt NULL; // primes_tableint pt_size 0; // primes_table 數量大小int init_primes_table(void){FILE* pFile;pFile fopen("primes_table.bin", "rb");if (pFile NULL) {fputs(&q…

【數據結構基礎筆記】【圖】

代碼參考《妙趣橫生的算法.C語言實現》 文章目錄前言1、圖的概念2、圖的存儲形式1、鄰接矩陣&#xff1a;2、鄰接表3、代碼定義鄰接表3、圖的創建4、深度優先搜索DFS5、廣度優先搜索BFS6、實例分析前言 本章總結&#xff1a;圖的概念、圖的存儲形式、鄰接表定義、圖的創建、圖…

第十六章 測試基礎

第十六章 測試基礎 在編譯型語言中&#xff0c;需要不斷重復編輯、編譯、運行的循環。 在Python中&#xff0c;不存在編譯階段&#xff0c;只有編輯和運行階段。測試就是運行程序。 先測試再編碼 極限編程先鋒引入了“測試一點點&#xff0c;再編寫一點點代碼”的理念。 換而…

如何蹭網

引言蹭網&#xff0c;在普通人的眼里&#xff0c;是一種很高深的技術活&#xff0c;總覺得肯定很難&#xff0c;肯定很難搞。還沒開始學&#xff0c;就已經敗給了自己的心里&#xff0c;其實&#xff0c;蹭網太過于簡單。我可以毫不夸張的說&#xff0c;只要你會windows的基本操…