feat: 添加 TCP 服务端与客户端示例项目

包含基于 Python socket 的多线程 TCP 服务端、交互式客户端、README 文档、MIT 许可证及 .gitignore。
这个提交包含在:
2026-08-24 10:59:43 +08:00
当前提交 52fa7c975e
共修改 6 个文件,包含 318 行新增和 0 行删除
+29
查看文件
@@ -0,0 +1,29 @@
# Python 字节码 / 缓存
__pycache__/
*.py[cod]
*$py.class
*.so
# 打包 / 安装产物
build/
dist/
*.egg-info/
.eggs/
# 虚拟环境
.venv/
venv/
env/
ENV/
# 代码编辑器 / IDE
.idea/
.vscode/
*.swp
# 操作系统文件
.DS_Store
Thumbs.db
# 本地测试日志(如有)
*.log
+21
查看文件
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 wangchuanli
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+115
查看文件
@@ -0,0 +1,115 @@
# TCP Server & Client (Python)
一个基于 Python 标准库 `socket` 实现的轻量级 TCP 通信示例项目,包含服务端和交互式客户端。
适合用于:
- 学习 TCP Socket 编程的基础流程
- 本地调试网络程序、验证端口连通性
- 作为其他 TCP 服务(如 Netty、自定义协议)的简易测试客户端
> ⚠️ 本项目仅用于学习和测试,未做并发处理、鉴权及安全防护,请勿直接用于生产环境。
## 项目结构
```
tcp_server/
├── tcp_server.py # TCP 服务端:监听端口、接收消息并返回确认
├── tcp_test.py # TCP 客户端:交互式发送消息、接收服务端响应
└── README.md # 项目文档
```
## 环境要求
- Python 3.6+(仅使用标准库,无需安装第三方依赖)
## 快速开始
### 1. 启动服务端
打开一个终端,运行服务端(默认监听 `0.0.0.0:30008`):
```bash
python tcp_server.py
```
启动成功后会看到:
```
🚀 服务器正在监听 0.0.0.0:30008 ...
等待客户端连接...
```
### 2. 启动客户端
另开一个终端,运行客户端并输入消息:
```bash
python tcp_test.py
```
```
正在尝试连接到 127.0.0.1:30008 ...
✅ 连接成功!请输入要发送的消息(输入 'exit' 退出):
我: hello
📤 消息已发送。
📥 服务器响应: 服务器已收到: hello
我: exit
正在断开连接...
```
### 3. 本机自测
如果服务端和客户端在同一台机器,客户端默认连接 `127.0.0.1:30008` 即可。
跨机器测试时,请将 `tcp_test.py` 中的 `HOST` 改为服务端的实际 IP。
## 配置说明
### 服务端 `tcp_server.py`
| 参数 | 默认值 | 说明 |
| ------- | ----------- | -------------------------------------- |
| `HOST` | `'0.0.0.0'` | 监听地址,`0.0.0.0` 表示接受所有接口 |
| `PORT` | `30008` | 监听端口,需与客户端保持一致 |
### 客户端 `tcp_test.py`
| 参数 | 默认值 | 说明 |
| ------- | ------------- | --------------------------------------------- |
| `HOST` | `'127.0.0.1'` | 服务端 IP,跨机测试请改为实际地址 |
| `PORT` | `30008` | 服务端端口,需与服务端保持一致 |
## 实现要点
### 服务端(`tcp_server.py`)
1. 创建 TCP Socket:`socket(AF_INET, SOCK_STREAM)`
2. 设置 `SO_REUSEADDR`,避免服务重启后端口处于 `TIME_WAIT` 导致绑定失败
3. `bind` 绑定地址,`listen(5)` 开始监听连接队列
4. 主循环不断 `accept` 新连接,每接受一个连接就创建一个守护线程 `handle_client` 处理,从而**支持并发多客户端**
5. 每个连接线程内循环 `recv(1024)` 接收数据,空数据表示客户端断开;收到消息后回送 `服务器已收到: <消息>`
6. 支持 `Ctrl+C` 优雅关闭;`finally` 中确保关闭监听套接字
> 使用 `threading.Thread(daemon=True)`,主线程退出时子线程会自动结束,便于调试与退出。
### 客户端(`tcp_test.py`)
1. 创建 TCP Socket 并 `connect` 到服务端
2. 通过 `input()` 循环读取用户输入并 `sendall` 发送(末尾追加 `\n`)
3. 发送后设置 5 秒超时等待服务端响应,超时或空响应均给出提示
4. 输入 `exit` 退出;任何情况下都在 `finally` 中关闭套接字
## 常见问题
**Q: 客户端提示 `ConnectionRefusedError`?**
A: 确认服务端已启动、端口一致,且防火墙未拦截该端口。
**Q: 服务端只处理一个连接?**
A: 已支持并发。服务端采用多线程模型(`threading`),每接受一个客户端连接就启动一个守护线程独立处理,可同时服务多个客户端。监听队列 `backlog` 设为 5,高并发长连接场景可结合连接池或 `selectors`/`asyncio` 进一步优化。
**Q: 可以和 Java Netty 等服务端互通吗?**
A: 客户端发送以 `\n` 结尾的消息,可对接按行分隔(如 `LineBasedFrameDecoder`)的协议方;服务端的回送逻辑为简单的 echo 确认。
## License
MIT
+8
查看文件
@@ -0,0 +1,8 @@
# 本项目仅使用 Python 标准库(socket、threading),无第三方依赖。
# 因此本文件为空,仅作工程规范占位。
#
# 若后续引入第三方库,请在此按如下格式列出(建议锁定版本):
# some-package==1.2.3
#
# 安装方式:
# pip install -r requirements.txt
+81
查看文件
@@ -0,0 +1,81 @@
import socket
import threading
def handle_client(conn, addr):
"""处理单个客户端连接(在独立线程中运行)。"""
print(f"✅ 客户端已连接: {addr}")
try:
# 接收数据循环
while True:
# 接收数据(缓冲区大小为 1024 字节)
data = conn.recv(1024)
# 如果没有收到数据,说明客户端已断开连接
if not data:
print(f"客户端已断开连接: {addr}")
break
# 解码并打印收到的消息
message = data.decode('utf-8')
print(f"📥 收到来自 {addr} 的消息: {message}")
# 可选:向客户端发送确认回复
response = f"服务器已收到: {message}"
conn.sendall(response.encode('utf-8'))
print(f"📤 已向 {addr} 发送确认回复。")
except Exception as e:
print(f"❌ 与 {addr} 通信发生错误: {e}")
finally:
# 关闭该客户端连接
conn.close()
print(f"与 {addr} 的连接已关闭。")
def tcp_server():
# --- 配置区域 ---
HOST = '0.0.0.0' # 监听所有网络接口
PORT = 30008 # 与客户端保持一致的端口
# -----------------
# 用于指示服务是否正在运行(便于后续扩展为可关闭)
server_socket = None
try:
# 1. 创建 TCP Socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置 SO_REUSEADDR 选项,允许重用地址和端口
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2. 绑定地址和端口
server_socket.bind((HOST, PORT))
# 3. 开始监听连接(backlog 调大以支持并发等待队列)
server_socket.listen(5)
print(f"🚀 服务器正在监听 {HOST}:{PORT} ...(支持并发连接)")
print("等待客户端连接...")
# 4. 循环接受客户端连接,每来一个连接就启动一个新线程
while True:
conn, addr = server_socket.accept()
client_thread = threading.Thread(
target=handle_client,
args=(conn, addr),
daemon=True,
)
client_thread.start()
print(f"🧵 当前活跃客户端线程数: {threading.active_count() - 1}")
except KeyboardInterrupt:
print("\n⛔ 收到中断信号,正在关闭服务器...")
except Exception as e:
print(f"❌ 发生错误: {e}")
finally:
# 5. 关闭监听套接字
if server_socket:
server_socket.close()
print("服务器已关闭。")
if __name__ == "__main__":
tcp_server()
+64
查看文件
@@ -0,0 +1,64 @@
import socket
def tcp_client():
# --- 配置区域 ---
# 服务器的 IP 地址或域名
HOST = '127.0.0.1' # 本地测试用;跨机器测试请改为服务端实际 IP
# 服务器的端口号
PORT = 30008 # 请确保此端口与服务器监听的端口一致
# -----------------
try:
# 1. 创建 TCP Socket 对象
# AF_INET 表示使用 IPv4 地址,SOCK_STREAM 表示使用 TCP 协议
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接到服务器
print(f"正在尝试连接到 {HOST}:{PORT} ...")
client_socket.connect((HOST, PORT))
print("✅ 连接成功!请输入要发送的消息(输入 'exit' 退出):")
# 3. 循环发送消息
while True:
message = input("我: ")
# 检查是否退出
if message.lower() == 'exit':
print("正在断开连接...")
break
# 4. 发送数据
# 网络传输的是字节流,所以需要将字符串编码为 bytes
# Netty服务端期望以换行符结尾的消息
client_socket.sendall(message.encode('utf-8')+b'\n')
print("📤 消息已发送。")
# 5. 接收服务端的响应
try:
# 设置超时时间,避免无限等待
client_socket.settimeout(5.0)
response = client_socket.recv(4096)
if response:
# 去除末尾的换行符并解码
response_str = response.decode('utf-8').rstrip('\n')
print(f"📥 服务器响应: {response_str}")
else:
print("⚠️ 服务端未返回响应")
except socket.timeout:
print("⚠️ 等待服务端响应超时")
finally:
# 恢复默认阻塞模式
client_socket.settimeout(None)
except ConnectionRefusedError:
print(f"❌ 连接失败:无法连接到 {HOST}:{PORT}。请确认服务器是否已启动且端口正确。")
except Exception as e:
print(f"❌ 发生错误:{e}")
finally:
# 5. 关闭连接
# 无论是否发生异常,都确保套接字被关闭
client_socket.close()
print("连接已关闭。")
if __name__ == "__main__":
tcp_client()