1.套接字(Socket)
套接字是网络通信的基本单元,它类似于电话线,用于在两个程序之间建立连接。在 Python 中,我们可以使用 socket 模块来创建和管理套接字。
import socket
# 创建一个 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定 IP 地址和端口
sock.bind(('localhost', 12345))
# 监听连接请求
sock.listen(5)
print("Server is listening on port 12345...")
# 接受客户端连接
client_socket, client_address = sock.accept()
print(f"Connection from {client_address}")
# 关闭连接
client_socket.close()
sock.close()
2.协议(Protocol)
协议是网络通信中的一组规则,定义了数据的格式、传输方式和错误处理等。常见的协议有 TCP 和 UDP。
- TCP:传输控制协议,提供可靠的、面向连接的服务。
- UDP:用户数据报协议,提供无连接的、不可靠的服务。
import socket
# 创建一个 UDP 套接字
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 发送数据
message = "Hello, UDP!"
udp_sock.sendto(message.encode(), ('localhost', 12345))
# 接收数据
data, addr = udp_sock.recvfrom(1024)
print(f"Received data: {data.decode()} from {addr}")
udp_sock.close()
3.客户端和服务器
在网络编程中,通常有一个客户端和一个服务器。服务器负责监听并处理来自客户端的请求,而客户端则向服务器发送请求并接收响应。
# 服务器端
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)
端口是网络通信中的逻辑地址,用于标识不同的应用程序或服务。端口号是一个 16 位的数字,范围从 0 到 65535。
import socket
# 创建一个 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 地址是互联网协议地址,用于唯一标识网络上的设备。IPv4 地址是一个 32 位的数字,通常表示为四个十进制数,每个数之间用点分隔。
import socket
# 获取本地主机的 IP 地址
host_ip = socket.gethostbyname(socket.gethostname())
print(f"Local host IP: {host_ip}")
6.阻塞与非阻塞
在网络编程中,套接字可以设置为阻塞模式或非阻塞模式。阻塞模式下,如果操作不能立即完成,程序会暂停等待;非阻塞模式下,如果操作不能立即完成,程序会立即返回一个错误。
import socket
# 创建一个非阻塞的 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(False) # 设置为非阻塞模式
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)
超时是指在网络操作中,如果在指定时间内没有完成,程序会自动放弃并返回一个错误。这在处理网络延迟或连接失败时非常有用。
import socket
# 创建一个 TCP 套接字并设置超时时间
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5) # 设置超时时间为 5 秒
try:
sock.connect(('localhost', 12345))
print("Connection successful!")
except socket.timeout:
print("Connection timed out.")
sock.close()
实战案例:简单的聊天应用
接下来,我们来实现一个简单的聊天应用,包括一个服务器和多个客户端。服务器负责接收和转发消息,客户端可以发送和接收消息。
服务器端代码:
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()
总结
今天我们学习了 Python 网络编程的 7 个基础概念,包括套接字、协议、客户端和服务器、端口、IP 地址、阻塞与非阻塞以及超时。通过这些概念,我们能够更好地理解和编写网络应用程序。最后,我们还实现了一个简单的聊天应用,展示了这些概念的实际应用。