问题: 实现一个简单的 Socket 客户端,核心步骤有哪些?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
TCP 客户端实现需四步:1. socket() 创建 IPv4 TCP 套接字;2. connect(('ip', port)) 向服务端发起三次握手,建立连接;3. sendall() 发送请求数据(确保完整发送),recv() 接收响应(返回 b'' 表示服务端已关闭连接);4. close() 关闭套接字释放文件描述符。全程必须捕获异常(如 ConnectionRefusedError、TimeoutError),并设置 settimeout 防止阻塞过久,核心原则:先连后发,发完即收,收完即关。
---
客户端四步流程与异常处理(标准骨架)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import socket
def run_client(): client = None try: client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.settimeout(5.0) client.connect(('127.0.0.1', 8080)) print("连接服务端成功") client.sendall(b'Hello, Server!') response = client.recv(1024) print(f"服务端响应: {response.decode()}") if not response: print("服务端已关闭连接") except socket.timeout: print("连接或接收超时") except ConnectionRefusedError: print("服务端未启动或端口不可达") except Exception as e: print(f"客户端异常: {e}") finally: if client: client.close()
if __name__ == "__main__": run_client()
|
关键方法速览
| 方法 |
作用 |
注意事项 |
socket() |
创建套接字对象 |
必须与服务端使用相同的协议族和类型(AF_INET + SOCK_STREAM) |
connect(addr) |
发起TCP三次握手连接 |
阻塞调用,失败抛异常(需try包裹);addr 为 (host, port) 元组 |
sendall(data) |
发送全部数据(内部循环直到发完) |
失败抛异常,推荐替代 send() 避免半发半收 |
recv(bufsize) |
从接收缓冲区读取数据 |
最大读取 bufsize 字节;返回 b'' 表示对端已FIN关闭 |
close() |
关闭连接,释放端口和文件描述符 |
必须在 finally 中确保执行,否则可能耗尽系统句柄 |
超时控制的必要性
connect() 和 recv() 默认由系统决定超时(可能长达数分钟),在高可用或交互式场景中需主动控制:
- 使用
socket.settimeout(seconds) 统一设置所有操作的超时。
- 超时发生时抛出
socket.timeout 异常,需单独捕获处理。
- 若需精细控制,可使用
select.select() 或 socket.setblocking(False) 配合非阻塞I/O。
客户端与服务端核心流程对照(巩固)
| 阶段 |
服务端 |
客户端 |
| 准备 |
socket() → bind() → listen() |
socket() |
| 建立连接 |
accept()(阻塞等待) |
connect()(发起握手) |
| 数据传输 |
recv() / send() |
sendall() / recv() |
| 结束通信 |
close()(监听套接字保持) |
close() |
| 注意点 |
accept() 返回新套接字处理每个客户端 |
recv() 收到 b'' 需立即 break 退出 |