python中socket模块常用吗_python网络学习笔记——socket模块使用记录
此文章記錄了筆者學(xué)習(xí)python網(wǎng)絡(luò)中socket模塊的筆記。
建議初次學(xué)習(xí)socket的讀者先讀一遍socket模塊主要函數(shù)的介紹。
socket模塊的介紹可以參考筆者的前一篇關(guān)于socket官方文檔的學(xué)習(xí)記錄:python網(wǎng)絡(luò)學(xué)習(xí)筆記——socket模塊官方文檔學(xué)習(xí)記錄。
一個簡單地socket客戶端(TCP)代碼(如果不懂代碼含義可以看我上篇文章)
import socket #導(dǎo)入socket模塊
port =80 #端口
host="www.baidu.com" #主機地址
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #創(chuàng)建套接字
s.connect((host,port)) #套接字連接
#向網(wǎng)站發(fā)送請求,注意參數(shù)時byte類型。不能是str(python3.7)。
s.sendall(b'GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:keep-alive\r\n\r\n')
while 1:
#從網(wǎng)頁接受1024bytes大小的數(shù)據(jù)
buf=s.recv(1024)
#在無數(shù)據(jù)是跳出循環(huán)
if not len(buf):
break
#打印數(shù)據(jù)
print(buf)
簡單的一個客戶端程序,但并不嚴謹。
如果用戶給了一個不存在的主機地址或沒有服務(wù)的端口地址,那么在套接字連接的過程中:s.connect((host,port))會產(chǎn)生socket.gaierror。對上述程序可以用sys模塊中的exit函數(shù)和try關(guān)鍵字來完善。
將套接字連接改為:
try:
s.connect((host,port))
except socket.gaierror as e:
print(e)
#退出程序
sys.exit(1)
以上完善程序過程僅僅是一個引入。在使用網(wǎng)絡(luò)模塊時可能會產(chǎn)生各種各樣的異常,在編程寫程序時應(yīng)盡量考慮到可能產(chǎn)生的異常與處理方法。其中try和except...as可能是我們調(diào)試時使用最多的工具了。
上述程序還有一個不方便的地方,就是數(shù)據(jù)呈現(xiàn)的方式。buf在每次循環(huán)得到的是一個1024字節(jié)的byte數(shù)據(jù)。byte數(shù)據(jù)在輸出時難以進行格式化的操作,并且1024字節(jié)大小的設(shè)置也很容易打亂原數(shù)據(jù)的格式。而套接字對象的makefile方法可以解決該問題。s.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None):
返回與套接字關(guān)聯(lián)的文件對象。返回的對象的具體類型取決于 makefile() 的參數(shù)。這些參數(shù)的解釋方式與內(nèi)置的 open() 函數(shù)相同,其中 mode 的值僅支持 'r' (默認),'w' 和 'b'。
makefile方法將byte操作轉(zhuǎn)化為文件操作,這對數(shù)據(jù)的格式化操作提供了很大的便利。
所以,上述打印數(shù)據(jù)代碼都可以換為以下內(nèi)容(建議找一個源碼比較少的網(wǎng)頁進行嘗試):
fd=s.makefile(mode='rb') #一定是rb,因為數(shù)據(jù)是byte類型
for i in fd.readlines(): #遍歷
print(i)
如果網(wǎng)頁的源碼過大的話,在打印過程中可能卡住。筆者在僅運行print(type(fd.readlines()))的情況下,電腦還是在1分鐘后給出結(jié)果。也可以使用fd.readline()進行數(shù)據(jù)第一行測試。
建立socket客戶端需要兩個步驟。首先建立socket對象,其次,將socket連接到遠程服務(wù)器上。
在建立ocket對象的時候,您需要告訴系統(tǒng)兩件事情:通信類型和協(xié)議家族。通信類型指明用什么協(xié)議來傳輸數(shù)據(jù)。協(xié)議的例子包括IPv4(當前的Intermet標準),IPv6(將來的Intermet.IPX/SPX(NerWare和AFP(Apple文件共享)。到目前為止,最通用的是IPv4;協(xié)議家族則定義數(shù)據(jù)如何被傳輸。協(xié)議家族一般是表示TCP通信的SOCKSTREAM或便是UDP的SOCK_DGRAM。
端口號
"端口"是英文port的意譯,可以認為是設(shè)備與外界通訊交流的出口。我們通過瀏覽器瀏覽的網(wǎng)頁一般是服務(wù)器的80端口。可自行百度常用端口地址。
UDP客戶端(不常用)
在socket被建立時,協(xié)議家族選擇SOCK_DGRAM。
UDP對數(shù)據(jù)的發(fā)送和接收沒有足夠的控制,在不調(diào)用connect方法時,可以通過sendto()方法和recvfrom()方法。s.recvfrom(bufsize[, flags]):
從套接字接收數(shù)據(jù)。返回值是一對 (bytes, address),其中 bytes 是字節(jié)對象,表示接收到的數(shù)據(jù),address 是發(fā)送端套接字的地址。
s.sendto(bytes, flags, address):
發(fā)送數(shù)據(jù)給套接字。本套接字不應(yīng)連接到遠程套接字,而應(yīng)由 address 指定目標套接字。返回發(fā)送字節(jié)數(shù)。
基本服務(wù)器操作
簡單服務(wù)器代碼:
import socekt
host='' #空字符代表可以接受任何主機的連接
port=51423 #可以選擇任何一個大于1024的端口
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #創(chuàng)建套接字
s.bind((host, port)) #套接字綁定
s.listen(1) #監(jiān)聽host的port,參數(shù)1表示最對有1個連接等待程序處理。
print("Server is running")
while True:
try:
##當有客戶端連接時,accept()方法會返回兩個信息,一個連接客戶端的套接字和連接主機地址
sock, addr = s.accept()
print(addr) #打印地址
except Exception as e:
print(e)
fd=sock.makefile(mode="rb')
print(fd.readline()) #打印數(shù)據(jù)第一行
fd.close() #關(guān)閉文件關(guān)聯(lián)
sock.close() #關(guān)閉客戶端套接字s.bind(address):
將套接字綁定到 address。套接字必須尚未綁定(套接字作為服務(wù)器時使用)。
s.listen([backlog]):
啟動一個作為服務(wù)器的套接字,用于接受連接(監(jiān)聽,方法名很直觀)。如果指定 backlog,則它最低為 0(小于 0 會被置為 0),它指定系統(tǒng)允許暫未 accept 的連接數(shù),超過后將拒絕新連接。未指定則自動設(shè)為合理的默認值 (套接字作為服務(wù)器時使用)。
s.accept():
接受一個連接。調(diào)用此方法的socket對象必須綁定到一個地址上并且監(jiān)聽連接。返回值是一個 (conn, address) 對,其中 conn 是一個 新的套接字對象,用于在此連接上收發(fā)數(shù)據(jù),address 是連接另一端的套接字所綁定的地址。(套接字作為服務(wù)器時使用)。
域名系統(tǒng)(DNS)
域名系統(tǒng)(DNS)是一個分布式的數(shù)據(jù)庫,主要用來把主機名轉(zhuǎn)換為IP地址。例如:將http://www.baidu.com 轉(zhuǎn)化為61.135.169.125。
socket的域名函數(shù)主要有:
socket.gethostbyname(host):
host是一個字符串的網(wǎng)址,返回解析之后的ip地址。
>>> socket.gethostbyname("www.baidu.com")
'61.135.169.125'
socket.gethostname():
無參數(shù),返回本機的主機名。
>>> socket.gethostname()
'HOST-TEST' #已做處理
socket.gethostbyname_ex(hostname):
將主機名轉(zhuǎn)換為 IPv4 地址格式的擴展接口。返回三元組 (hostname, aliaslist, ipaddrlist),其中 hostname 是響應(yīng)給定 ip_address 的主要主機名,aliaslist 是相同地址的其他可用主機名的列表(可能為空),而 ipaddrlist 是 IPv4 地址列表,包含相同主機名、相同接口的不同地址(通常是一個地址,但不總是如此)。(一個ip可能對應(yīng)多個域名,一個域名也可對應(yīng)多個ip。)
>>> socket.gethostbyname_ex('www.baidu.com')
('www.a.shifen.com', ['www.baidu.com'], ['61.135.169.121', '61.135.169.125'])
注:bind()函數(shù)的第一個參數(shù)為空時,意思為可以綁定多有接口和地址。在只希望一個特定的地址鏈接時,可以指定參數(shù)。
對數(shù)據(jù)進行完整性檢查,注意信息丟失情況的TCP更適合客戶端。而在服務(wù)器端,UDP不需要考慮丟包情況,更加適合。
死鎖發(fā)生在當一個服務(wù)器和客戶端同時往同一個連接上寫東西和同時從一個連接上讀的時候。在這些情況下,沒有進程可以得到任何的數(shù)據(jù)。
總結(jié):
以上只是套接字的基礎(chǔ)使用。不過在使用python進行網(wǎng)絡(luò)編程時,socket模塊很少使用。python有更高級的網(wǎng)絡(luò)模塊。
ps.此專欄是筆者學(xué)習(xí)《python網(wǎng)絡(luò)編程基礎(chǔ)》的學(xué)習(xí)筆記。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的python中socket模块常用吗_python网络学习笔记——socket模块使用记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python画父子关系图_将有父子关系的
- 下一篇: websocket python爬虫_p