socket库是Python标准库的一部分,提供了底层的网络接口,可以用于实现各种网络协议的通信。在网络编程中,socket(套接字)是一种在网络设备之间通信的端点。Python的socket库使得网络编程变得简单且高效,能够处理TCP/IP、UDP等协议。
1. socket库的基本概念
- Socket(套接字):Socket是网络通信的基本单元,既可以是一个客户端,也可以是一个服务器。Socket可以绑定到特定的IP地址和端口号,通过这个绑定来实现网络通信,接收来自该地址和端口的数据,或发送数据到该地址和端口。
- Address Family:指定使用的地址类型,如IPv4或IPv6。
- AF_INET:用于IPv4
- AF_INET6:用于IPv6
- Socket Type:指定使用的通信协议,如TCP或UDP。
- SOCK_STREAM:面向连接的流式Socket,使用TCP协议。
- SOCK_DGRAM:面向无连接的数据报Socket,使用UDP协议。
2. socket库常用类与方法
2.1 Socket对象
创建Socket对象的方法:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
这是一个TCP Socket,指定了AF_INET(IPv4)和SOCK_STREAM(TCP)。
# 创建TCP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建UDP Socket
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
2.2 绑定地址和端口
服务器端需要将Socket绑定到指定的地址和端口,使用bind()
方法将Socket绑定到指定的IP地址和端口号。
s.bind(('localhost', 8080))
2.3 监听连接(仅适用于TCP服务器)
服务器端使用**listen()**方法来开始监听连接。
s.listen(5) # 参数指定可以排队的最大连接数
2.4 接受连接(仅适用于TCP服务器)
服务器端使用accept()方法来接受客户端的连接,该方法会阻塞直到有客户端连接,返回一个新的Socket对象表示客户端连接。
connection, client_address = s.accept()
print(f"Connection from {client_address}")
2.5 连接到服务器(仅适用于TCP客户端)
客户端使用connect()
方法连接到服务器。
s.connect(('localhost', 8080))
2.6 发送和接收数据
对于TCP,使用send()
,sendall()
和recv()
方法来发送和接收数据包。
- send():发送数据
- sendall():发送数据,确保整个消息发送完毕
- recv():接收数据
s.send(b'Hello, World!') # 发送字节数据
data = connection.recv(1024) # 参数1024表示接收的最大字节数
对于UDP,使用sendto()
和recvfrom()
方法来发送和接收数据包。
s.sendto(b'Hello, UDP!', ('localhost', 8080))
data, addr = s.recvfrom(1024)
2.7 关闭Socket
close()
方法用于关闭Socket连接。
s.close()
2.8 常见套接字方法
socket.gethostname()
:获取当前主机名。socket.gethostbyname(hostname)
:根据主机名获取 IPv4 地址。socket.gethostbyname_ex(hostname)
:获取主机名、别名列表以及对应的所有 IP 地址。socket.getaddrinfo(host, port)
:获取主机和端口的地址信息列表。
3. 高级功能
3.1 设置Socket选项
使用setsockopt()
方法可以设置Socket的选项,可以设置重用地址选项:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
在频繁重启服务器或快速重新启动服务器时,可以避免由于端口被占用而导致的绑定失败。当运行一个服务器时,如果不设置 SO_REUSEADDR,当关闭服务器后,可能需要等待几分钟才能重新绑定到同一端口。但设置这个选项后,可以立即重新绑定同一端口。
3.2 设置超时
settimeout()
方法设置Socket操作的超时时间,防止无限期阻塞。
s.settimeout(5.0) # 设置超时为5秒
3.3 非阻塞模式
setblocking()
方法可以将Socket设置为非阻塞模式,调用后立即返回,即使没有数据可读或写。
s.setblocking(False)
4. 常用异常处理
网络编程中常会遇到各种异常情况,如连接失败、数据发送失败等。socket库提供了相应的异常类来捕获和处理这些情况。
- socket.error:所有Socket错误的基类。
- socket.timeout:操作超时。
- socket.herror:主机相关的错误。
- socket.gaierror:地址相关的错误。
try:
s.connect(('localhost', 8080))
except socket.timeout:
print("Connection timed out!")
except socket.error as e:
print(f"Socket error: {e}")
5. 常见用例
5.1 创建TCP服务器
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8080))
server_socket.listen(5)
print("Server is listening on port 8080...")
while True:
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address}")
data = client_socket.recv(1024)
if data:
print(f"Received: {data.decode('utf-8')}")
client_socket.sendall(data) # 回显接收到的数据
client_socket.close()
5.2 创建TCP客户端
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 8080))
client_socket.sendall(b'Hello, Server!')
data = client_socket.recv(1024)
print(f"Received: {data.decode('utf-8')}")
client_socket.close()
5.3 创建UDP服务器
import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(('localhost', 8080))
print("UDP server is listening on port 8080...")
while True:
data, client_address= udp_socket.recvfrom(1024)
print(f"Received from {client_address}: {data.decode('utf-8')}")
udp_socket.sendto(data, client_address)
5.4 创建UDP客户端
import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 8080)
udp_socket.sendto(b'Hello, UDP Server!', server_address)
data, server = udp_socket.recvfrom(1024)
print(f"Received {data.decode('utf-8')} from {server}")
udp_socket.close()
6. 多线程或多进程处理
在实现高并发服务器时,通常需要使用多线程或多进程来处理多个客户端的连接。Python的threading和multiprocessing模块可以与socket库结合使用。
7. socket库的扩展
Python还提供了socketserver模块,这是socket库的高级封装,提供了更加方便的方式来创建网络服务器。你可以根据需要选择使用。