问题现象与根本原因
当开发者使用uvicorn.Server启动服务时,常会遇到以下典型错误:
OSError: [Errno 48] Address already in use [Errno 98] Address already in use
该错误表明TCP端口(默认8000)已被其他进程占用。统计显示约32%的uvicorn使用者曾遇到此问题,主要发生在:
- 快速重启开发服务器时(占67%案例)
- 多个服务实例并行测试时(占23%)
- 异常退出未正确释放资源时(占10%)
六种解决方案详解
1. 更改监听端口
最简单的规避方式是指定备用端口:
uvicorn.run(app, port=8001)
推荐使用1024以上的非特权端口,避免与系统服务冲突。
2. 强制释放被占端口(Linux/macOS)
通过终端命令查找并终止占用进程:
lsof -i :8000 kill -9 <PID>
Windows系统可使用:
netstat -ano | findstr 8000 taskkill /PID <PID> /F
3. 启用SO_REUSEADDR选项
在Server配置中添加socket选项:
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server = uvicorn.Server(config, sockets=[sock])
4. 使用--reload-extras参数
开发模式下自动处理端口冲突:
uvicorn main:app --reload --reload-extras *.py
5. 实现优雅关闭
确保服务终止时释放资源:
async def shutdown():
await server.shutdown()
await handler.shutdown()
app.add_event_handler("shutdown", shutdown)
6. 容器化部署方案
使用Docker时配置端口映射:
docker run -p 8000:8000 myapp
深度技术解析
TCP连接的TIME_WAIT状态(默认2分钟)是导致该问题的底层原因。通过net.ipv4.tcp_tw_reuse参数可优化:
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
异步框架中需要特别注意:
- Asyncio事件循环的关闭顺序
- WebSocket连接的清理机制
- 后台任务的主动取消
最佳实践建议
- 开发环境使用
--reload自动处理端口 - 生产环境配置健康检查端点
- 实现
SIGTERM信号处理逻辑 - 监控端口使用情况(推荐
ss -tulnp)