Python 網(wǎng)絡(luò)編程的七個基礎(chǔ)概念
網(wǎng)絡(luò)編程是 Python 編程中的一個重要領(lǐng)域,它涉及到如何通過網(wǎng)絡(luò)發(fā)送和接收數(shù)據(jù)。今天我們就來聊聊 Python 網(wǎng)絡(luò)編程的七個基礎(chǔ)概念,幫助你更好地理解和使用網(wǎng)絡(luò)編程。
1.套接字(Socket)
套接字是網(wǎng)絡(luò)通信的基本單元,它類似于電話線,用于在兩個程序之間建立連接。在 Python 中,我們可以使用 socket 模塊來創(chuàng)建和管理套接字。
import socket
# 創(chuàng)建一個 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 綁定 IP 地址和端口
sock.bind(('localhost', 12345))
# 監(jiān)聽連接請求
sock.listen(5)
print("Server is listening on port 12345...")
# 接受客戶端連接
client_socket, client_address = sock.accept()
print(f"Connection from {client_address}")
# 關(guān)閉連接
client_socket.close()
sock.close()
2.協(xié)議(Protocol)
協(xié)議是網(wǎng)絡(luò)通信中的一組規(guī)則,定義了數(shù)據(jù)的格式、傳輸方式和錯誤處理等。常見的協(xié)議有 TCP 和 UDP。
- TCP:傳輸控制協(xié)議,提供可靠的、面向連接的服務(wù)。
- UDP:用戶數(shù)據(jù)報協(xié)議,提供無連接的、不可靠的服務(wù)。
import socket
# 創(chuàng)建一個 UDP 套接字
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 發(fā)送數(shù)據(jù)
message = "Hello, UDP!"
udp_sock.sendto(message.encode(), ('localhost', 12345))
# 接收數(shù)據(jù)
data, addr = udp_sock.recvfrom(1024)
print(f"Received data: {data.decode()} from {addr}")
udp_sock.close()
3.客戶端和服務(wù)器
在網(wǎng)絡(luò)編程中,通常有一個客戶端和一個服務(wù)器。服務(wù)器負(fù)責(zé)監(jiān)聽并處理來自客戶端的請求,而客戶端則向服務(wù)器發(fā)送請求并接收響應(yīng)。
# 服務(wù)器端
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(5)
print("Server is listening on port 12345...")
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address}")
data = client_socket.recv(1024)
print(f"Received data: {data.decode()}")
client_socket.sendall("Hello, Client!".encode())
client_socket.close()
server_socket.close()
# 客戶端
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))
client_socket.sendall("Hello, Server!".encode())
data = client_socket.recv(1024)
print(f"Received data: {data.decode()}")
client_socket.close()
4.端口(Port)
端口是網(wǎng)絡(luò)通信中的邏輯地址,用于標(biāo)識不同的應(yīng)用程序或服務(wù)。端口號是一個 16 位的數(shù)字,范圍從 0 到 65535。
import socket
# 創(chuàng)建一個 TCP 套接字并綁定到特定端口
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8080)) # 綁定到 8080 端口
server_socket.listen(5)
print("Server is listening on port 8080...")
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address}")
client_socket.close()
server_socket.close()
5.IP 地址
IP 地址是互聯(lián)網(wǎng)協(xié)議地址,用于唯一標(biāo)識網(wǎng)絡(luò)上的設(shè)備。IPv4 地址是一個 32 位的數(shù)字,通常表示為四個十進制數(shù),每個數(shù)之間用點分隔。
import socket
# 獲取本地主機的 IP 地址
host_ip = socket.gethostbyname(socket.gethostname())
print(f"Local host IP: {host_ip}")
6.阻塞與非阻塞
在網(wǎng)絡(luò)編程中,套接字可以設(shè)置為阻塞模式或非阻塞模式。阻塞模式下,如果操作不能立即完成,程序會暫停等待;非阻塞模式下,如果操作不能立即完成,程序會立即返回一個錯誤。
import socket
# 創(chuàng)建一個非阻塞的 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(False) # 設(shè)置為非阻塞模式
try:
sock.connect(('localhost', 12345))
except BlockingIOError:
print("Connection attempt is in progress...")
# 檢查連接是否成功
if sock.getpeername():
print("Connection successful!")
else:
print("Connection failed.")
sock.close()
7.超時(Timeout)
超時是指在網(wǎng)絡(luò)操作中,如果在指定時間內(nèi)沒有完成,程序會自動放棄并返回一個錯誤。這在處理網(wǎng)絡(luò)延遲或連接失敗時非常有用。
import socket
# 創(chuàng)建一個 TCP 套接字并設(shè)置超時時間
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5) # 設(shè)置超時時間為 5 秒
try:
sock.connect(('localhost', 12345))
print("Connection successful!")
except socket.timeout:
print("Connection timed out.")
sock.close()
實戰(zhàn)案例:簡單的聊天應(yīng)用
接下來,我們來實現(xiàn)一個簡單的聊天應(yīng)用,包括一個服務(wù)器和多個客戶端。服務(wù)器負(fù)責(zé)接收和轉(zhuǎn)發(fā)消息,客戶端可以發(fā)送和接收消息。
服務(wù)器端代碼:
import socket
import threading
def handle_client(client_socket, client_address, clients):
while True:
try:
message = client_socket.recv(1024).decode()
if not message:
break
print(f"Message from {client_address}: {message}")
broadcast_message(message, clients, client_socket)
except:
break
print(f"Client {client_address} disconnected.")
client_socket.close()
clients.remove(client_socket)
def broadcast_message(message, clients, sender_socket):
for client in clients:
if client != sender_socket:
client.sendall(message.encode())
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(5)
print("Server is listening on port 12345...")
clients = []
while True:
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address}")
clients.append(client_socket)
thread = threading.Thread(target=handle_client, args=(client_socket, client_address, clients))
thread.start()
if __name__ == "__main__":
start_server()
客戶端代碼:
import socket
import threading
def receive_messages(client_socket):
while True:
try:
message = client_socket.recv(1024).decode()
if not message:
break
print(message)
except:
break
def send_messages(client_socket):
while True:
message = input()
client_socket.sendall(message.encode())
def start_client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))
receive_thread = threading.Thread(target=receive_messages, args=(client_socket,))
receive_thread.start()
send_thread = threading.Thread(target=send_messages, args=(client_socket,))
send_thread.start()
if __name__ == "__main__":
start_client()
總結(jié)
今天我們學(xué)習(xí)了 Python 網(wǎng)絡(luò)編程的 7 個基礎(chǔ)概念,包括套接字、協(xié)議、客戶端和服務(wù)器、端口、IP 地址、阻塞與非阻塞以及超時。通過這些概念,我們能夠更好地理解和編寫網(wǎng)絡(luò)應(yīng)用程序。最后,我們還實現(xiàn)了一個簡單的聊天應(yīng)用,展示了這些概念的實際應(yīng)用。