Python模块详解(一)—— socket 和 threading 模块

(一)Python socket 模块详解

socket 模块提供了对 Berkeley sockets API 的访问,是实现网络通信的基础。通过它,可以创建客户端和服务器,进行 TCP 或 UDP 数据传输。

1. 核心概念

(1)地址族(Address Family):指定通信使用的协议。

AF_INET:IPv4(最常用)

AF_INET6:IPv6

AF_UNIX:Unix 域套接字(本地进程间通信)

(2)套接字类型(Socket Type)

SOCK_STREAM:面向连接的可靠字节流(TCP)

SOCK_DGRAM:无连接的数据报(UDP)

SOCK_RAW:原始套接字(通常需要管理员权限)

(3)协议(Protocol):通常设为 0,让系统自动选择。

2. 主要函数与方法

(1)创建 socket

python 复制代码
import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0)

family:默认为 AF_INET,type:默认为 SOCK_STREAM。

(2)服务器端常用方法

bind(address):将套接字绑定到指定地址(IP 和端口)。

address 格式:(host, port),例如 ('127.0.0.1', 8888)。

listen([backlog]):开始监听连接请求。backlog 指定最大挂起连接数。

accept():阻塞等待客户端连接,返回 (conn, address),其中 conn 是新的套接字对象,用于与客户端通信。

(3)客户端常用方法

connect(address):连接到远程服务器。

connect_ex(address):类似 connect(),但返回错误码而不是抛出异常。

(4)数据收发

send(bytes):发送数据,返回实际发送的字节数(可能小于数据长度)。

可使用 sendall() 确保全部发送。

recv(bufsize[, flags]):接收数据,最多 bufsize 字节,返回接收到的字节串。

sendto(bytes, address):UDP 发送数据到指定地址。

recvfrom(bufsize):UDP 接收数据,返回 (data, address)。

(5)控制选项

setsockopt(level, optname, value) / getsockopt(level, optname):设置/获取套接字选项。例如 socket.SO_REUSEADDR 允许重用地址。

setblocking(flag):设置阻塞模式。flag=False 时套接字为非阻塞,若操作无法立即完成则抛出 BlockingIOError。

settimeout(value):设置超时时间(秒)。超时后操作抛出 timeout 异常。

(6)关闭套接字

close():释放资源。

(7)辅助函数

gethostname():获取本地主机名。

gethostbyname(hostname):将主机名解析为 IPv4 地址。

gethostbyaddr(ip_address):反向解析。

getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):获取地址信息列表,是编写协议无关代码的推荐方式。

3. 使用示例

(1)TCP 服务器

具体示例如下:

python 复制代码
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 允许端口重用
server.bind(('0.0.0.0', 8888))
server.listen(5)
print("Server listening on port 8888")

while True:
    conn, addr = server.accept()
    print(f"Connected by {addr}")
    data = conn.recv(1024)
    if data:
        conn.sendall(b"Received: " + data)
    conn.close()

(2)TCP 客户端

具体示例如下:

python 复制代码
import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8888))
client.sendall(b"Hello, server!")
response = client.recv(1024)
print("Received:", response)
client.close()

(3)UDP 服务器

python 复制代码
import socket

udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_server.bind(('0.0.0.0', 8889))
while True:
    data, addr = udp_server.recvfrom(1024)
    print(f"Message from {addr}: {data}")
    udp_server.sendto(b"ACK", addr)

4. 注意事项

  • 异常处理 :网络操作可能引发 socket.error、timeout 等异常,应使用 try/except 捕获。
  • 阻塞与非阻塞 :默认情况下,accept()、recv() 等会阻塞线程,可使用 setblocking(False) 或 settimeout() 改变行为。
  • 字节与字符串 :网络传输的是字节数据,发送前需将字符串编码(如 encode()),接收后解码(decode())。

(二)Python threading 模块详解

threading 模块提供了高级的多线程编程接口,允许在单个进程中并发执行多个任务。

1. 核心概念

(1)线程(Thread):轻量级进程,共享进程的内存空间。

(2)全局解释器锁(GIL):CPython 中,GIL 使得同一时刻只有一个线程执行 Python 字节码,因此多线程并不能充分利用多核 CPU 进行并行计算,但在 I/O 密集型任务中依然有效。

(3)线程安全:多个线程同时访问共享数据时,需要同步机制避免数据竞争。

2. 主要类与函数

(1)Thread 类

创建线程:

python 复制代码
 t = threading.Thread(target=func, args=(arg1,), kwargs={}, name='Thread-1')

其中:

target:线程执行的函数。

args:位置参数元组。

kwargs:关键字参数字典。

name:线程名称。

启动线程:

python 复制代码
t.start()

等待线程结束:

python 复制代码
t.join(timeout)

阻塞直到线程终止。

其他属性:t.ident(线程标识符)、t.is_alive()(是否存活)、t.daemon(是否为守护线程)。

(2)线程同步原语

Lock:互斥锁。

  • acquire(blocking=True, timeout=-1):获取锁,可阻塞。
  • release():释放锁。

示例:

python 复制代码
lock = threading.Lock()
lock.acquire()
# 临界区
lock.release()

更推荐使用 with lock: 上下文管理器。

RLock:可重入锁,同一线程可多次获取,避免死锁。

Semaphore:信号量,允许一定数量的线程同时访问资源。

Event:事件,用于线程间通信。set()、wait()、clear()。

Condition:条件变量,可用于生产者-消费者模式。

线程间通信

queue.Queue:线程安全的队列,常用于数据交换。

  • put(item):入队。
  • get():出队,若队列空则阻塞。

(3)模块级函数

threading.active_count():当前存活的线程数。

threading.current_thread():返回当前线程对象。

threading.enumerate():返回所有存活线程的列表。

threading.main_thread():返回主线程对象。

3. 使用示例

(1)创建并启动线程

python 复制代码
import threading

import time

def worker(name):
    print(f"Thread {name} starting")
    time.sleep(2)
    print(f"Thread {name} finished")

threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(i,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()
print("All threads done")

(2)使用锁避免竞争条件

python 复制代码
import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(counter)  # 正确输出 200000

(3)使用 Queue 进行线程间通信(生产者-消费者)

python 复制代码
import threading
import queue
import time

def producer(q):
    for i in range(5):
        item = f"item-{i}"
        q.put(item)
        print(f"Produced {item}")
        time.sleep(1)
    q.put(None)  # 结束信号

def consumer(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(f"Consumed {item}")
        time.sleep(1.5)

q = queue.Queue()
t1 = threading.Thread(target=producer, args=(q,))
t2 = threading.Thread(target=consumer, args=(q,))
t1.start()
t2.start()
t1.join()
t2.join()

4. 注意事项

  • 守护线程(Daemon Thread) :设置 t.daemon = True(或在构造时指定),主线程退出时守护线程会自动终止,不会等待。
  • 避免死锁 :多个锁嵌套使用时,确保获取顺序一致,或使用 RLock。
  • 线程安全 :不要共享可变对象而不加锁,使用 Queue 或 threading 同步原语。
  • GIL 的影响 :对于 CPU 密集型任务,多线程可能比单线程还慢,可考虑 multiprocessing 模块。

(三)socket 和 threading 结合使用

socket 和 threading 常结合使用,例如在多线程服务器中,每个客户端连接分配一个线程处理。典型模式:

python 复制代码
import socket
import threading

def handle_client(conn, addr):
    with conn:
        print(f"Thread {threading.current_thread().name} handling {addr}")
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

server = socket.socket()
server.bind(('0.0.0.0', 8888))
server.listen(5)
while True:
    conn, addr = server.accept()
    t = threading.Thread(target=handle_client, args=(conn, addr))
    t.start()

这样每个连接独立处理,主线程继续等待新连接。

相关推荐
csbysj20202 小时前
桥接模式(Bridge Pattern)
开发语言
Jay-r2 小时前
OpenClaw养龙虾工具安全风险分析:五大隐患及防护建议引言
网络·python·安全·web安全·ai助手·openclaw
Yupureki2 小时前
《C++实战项目-高并发内存池》4.CentralCache构造
c语言·开发语言·c++·单例模式·github
2401_898075122 小时前
分布式系统监控工具
开发语言·c++·算法
C蔡博士3 小时前
最近点对问题(Closest Pair of Points)
java·python·算法
APIshop3 小时前
Java调用亚马逊商品详情API接口完全指南
java·开发语言·python
lsx2024063 小时前
PostgreSQL中的NULL处理
开发语言
是梦终空1163 小时前
模板编译期机器学习
开发语言·c++·算法
艾莉丝努力练剑3 小时前
文件描述符fd:跨进程共享机制
java·linux·运维·服务器·开发语言·c++