一文詳解Python中socket庫(kù)的完整使用教程
一、socket 簡(jiǎn)介
Socket 又稱(chēng)套接字,是應(yīng)用程序與網(wǎng)絡(luò)傳輸層之間的接口,所有網(wǎng)絡(luò)通信都基于 Socket。
Python 內(nèi)置 socket 模塊,無(wú)需額外安裝,可以直接完成 TCP、UDP 通信。
網(wǎng)絡(luò)兩大傳輸協(xié)議:
- TCP(SOCK_STREAM):面向連接、可靠、三次握手,不會(huì)丟包。
- UDP(SOCK_DGRAM):無(wú)連接、不可靠,直接發(fā)送數(shù)據(jù)包,速度更快。
導(dǎo)入模塊:
import socket
二、socket 對(duì)象創(chuàng)建
語(yǔ)法
socket.socket(family, type)
family=socket.AF_INET:IPv4(最常用)type=socket.SOCK_STREAM:TCPtype=socket.SOCK_DGRAM:UDP
示例:
# 創(chuàng)建TCP套接字 tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 創(chuàng)建UDP套接字 udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
第一部分:TCP 通信全套API
TCP通信分為客戶(hù)端和服務(wù)端。
1. TCP 客戶(hù)端常用方法
| 方法 | 作用 |
|---|---|
connect((host, port)) | 和服務(wù)端建立TCP連接 |
send(bytes) | 發(fā)送字節(jié)數(shù)據(jù) |
recv(buffer_size) | 接收數(shù)據(jù),返回bytes |
settimeout(n) | 設(shè)置阻塞超時(shí)時(shí)間 |
close() | 關(guān)閉套接字 |
完整客戶(hù)端代碼
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5) # 5秒無(wú)響應(yīng)則超時(shí)
# 建立連接
sock.connect(("127.0.0.1", 8080))
# 發(fā)送數(shù)據(jù),只能發(fā)送bytes
sock.send("你好服務(wù)端".encode("utf-8"))
# 接收數(shù)據(jù),最多讀取1024字節(jié)
data = sock.recv(1024)
print(data.decode("utf-8"))
sock.close()
2. TCP 服務(wù)端常用方法
| 方法 | 作用 |
|---|---|
bind((ip, port)) | 綁定本機(jī)IP與端口 |
listen(n) | 開(kāi)啟監(jiān)聽(tīng),n為等待隊(duì)列長(zhǎng)度 |
accept() | 阻塞等待客戶(hù)端接入,返回(conn, address) |
完整服務(wù)端代碼
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 端口復(fù)用,避免重啟時(shí)報(bào)端口被占用
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("0.0.0.0", 8080))
server.listen(5)
print("服務(wù)端已啟動(dòng),等待連接...")
# 阻塞等待客戶(hù)端
conn, client_addr = server.accept()
print("客戶(hù)端地址:", client_addr)
# 接收消息
msg = conn.recv(1024)
print("收到:", msg.decode())
# 回復(fù)消息
conn.send("收到消息".encode("utf-8"))
# 關(guān)閉當(dāng)前客戶(hù)端連接
conn.close()
第二部分:UDP 通信全套API
UDP 不需要建立連接,沒(méi)有 connect(可選),核心方法只有兩個(gè):
| 方法 | 作用 |
|---|---|
sendto(data, (ip, port)) | 發(fā)送數(shù)據(jù)并指定目標(biāo)地址 |
recvfrom(buffer) | 接收數(shù)據(jù),同時(shí)獲取發(fā)送方地址 |
1. UDP客戶(hù)端(只發(fā)數(shù)據(jù))
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 發(fā)送UDP數(shù)據(jù)包
sock.sendto(b"心跳包", ("127.0.0.1", 9999))
sock.close()
2. UDP服務(wù)端接收數(shù)據(jù)
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 9999))
while True:
data, addr = sock.recvfrom(1024)
print(f"來(lái)自{addr}: {data.decode()}")
# 回包
sock.sendto(b"ok", addr)
3. UDP廣播設(shè)置
局域網(wǎng)設(shè)備發(fā)現(xiàn)必備:
# 開(kāi)啟廣播權(quán)限
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(b"online", ("255.255.255.255", 9999))
三、socket 高頻通用配置選項(xiàng)
1. 端口復(fù)用(必加)
解決服務(wù)端重啟提示 Address already in use
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
2. 設(shè)置阻塞超時(shí)
recv、accept 默認(rèn)永久阻塞,必須加超時(shí)防止程序卡死
sock.settimeout(3)
捕獲異常:
try:
data = sock.recv(1024)
except socket.timeout:
print("接收超時(shí)")
3. 關(guān)閉Nagle算法,小包立即發(fā)送
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
4. 獲取本機(jī)IP
socket.gethostbyname(socket.gethostname())
5. 域名解析為IP
socket.gethostbyname("www.baidu.com")
四、TCP 經(jīng)典問(wèn)題:粘包問(wèn)題
TCP是字節(jié)流,沒(méi)有數(shù)據(jù)包邊界,多次發(fā)送的數(shù)據(jù)會(huì)粘在一起。
解決方案:
- 固定每條消息長(zhǎng)度;
- 先發(fā)送數(shù)據(jù)長(zhǎng)度,再發(fā)送正文;
- 使用換行符、特殊字符做分隔。
簡(jiǎn)單分隔示例:
# 發(fā)送端 sock.send(b"hello|||") # 接收端按分隔符切割數(shù)據(jù)
五、常用實(shí)戰(zhàn)小案例
案例1:TCP端口存活檢測(cè)
def port_check(host, port, timeout=2):
try:
sock = socket.socket()
sock.settimeout(timeout)
sock.connect((host, port))
sock.close()
return True
except:
return False
案例2:裸Socket發(fā)送HTTP請(qǐng)求(不使用requests)
sock = socket.socket()
sock.connect(("www.baidu.com", 80))
http_header = b"GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:close\r\n\r\n"
sock.send(http_header)
print(sock.recv(4096).decode("utf-8", errors="ignore"))
sock.close()
六、核心方法匯總表
TCP專(zhuān)用
- connect()
- listen()
- bind()
- accept()
- send()
- recv()
UDP專(zhuān)用
- sendto()
- recvfrom()
公共方法
- settimeout()
- setsockopt()
- close()
七、避坑總結(jié)
- 所有收發(fā)數(shù)據(jù)必須是
bytes,字符串必須.encode("utf-8"); - TCP必須先連接再收發(fā),UDP直接發(fā)包;
- recv緩沖區(qū)要合理設(shè)置,太小會(huì)讀不全數(shù)據(jù);
- 一定要設(shè)置超時(shí),避免無(wú)限阻塞;
- 服務(wù)端綁定
0.0.0.0才能對(duì)外網(wǎng)與局域網(wǎng)開(kāi)放;綁定127.0.0.1僅本機(jī)訪(fǎng)問(wèn); - 短連接收發(fā)完畢及時(shí)close,避免大量TIME_WAIT占用端口。
如果你需要,我可以繼續(xù)寫(xiě):
- 多線(xiàn)程TCP服務(wù)端
- asyncio異步socket并發(fā)探測(cè)
- 自定義TCP分包協(xié)議解決粘包完整版代碼。
到此這篇關(guān)于一文詳解Python中socket庫(kù)的完整使用教程的文章就介紹到這了,更多相關(guān)Python socket庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
TensorFlow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)
這篇文章主要為大家詳細(xì)介紹了TensorFlow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
Python?tkinter庫(kù)繪圖實(shí)例分享
這篇文章主要給大家分享了Python?tkinter庫(kù)繪圖實(shí)例,主要分享實(shí)例有小房子繪制、彩色氣泡動(dòng)畫(huà)繪制內(nèi)容,需要的小伙伴可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助2022-04-04
python中pandas.DataFrame排除特定行方法示例
這篇文章主要給大家介紹了關(guān)于python中pandas.DataFrame排除特定行的方法,文中給出了詳細(xì)的示例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03
開(kāi)始著手第一個(gè)Django項(xiàng)目
這篇文章主要介紹了開(kāi)始著手第一個(gè)Django項(xiàng)目的過(guò)程,Django是豐富多彩的Python框架中人氣最高的一個(gè),功能多而全,需要的朋友可以參考下2015-07-07

