本地服务明明起了,客户端一连就报 Connection refused;或者 telnet 端口是通的,程序却收不到数据。排查这类问题,得回到 socket 编程的基本流程上,很多毛病出在某一步被跳过了。
socket 是什么
socket 可以理解成网络通信两端的插座:IP 地址定位到机器,端口号定位到机器上的进程,两者合起来就是一条链路的两端。常用的有两种:TCP 先握手再传数据,可靠不丢;UDP 直接发,快但不保证到达。
服务端和客户端各做什么
以 TCP 为例,服务端固定四步:创建 socket、bind 绑定地址和端口、listen 开始监听、accept 等连接进来。客户端简单些:创建 socket,connect 目标 IP 和端口,连上后用 send 和 recv 收发数据。用 Python 写个最小服务端就这么几行:
import socket; s = socket.socket(); s.bind(('0.0.0.0', 9000)); s.listen(5); conn, addr = s.accept(); print(conn.recv(1024)); conn.send(b'ok')
新手常踩的坑
- bind 绑了固定内网 IP,换台机器就起不来,一般写 0.0.0.0 监听所有网卡
- 服务重启报 Address already in use,是端口处于 TIME_WAIT,可设置 SO_REUSEADDR 解决
- send 返回成功不代表对方收到,TCP 只保证数据进了本机协议栈
- recv 一次收到的字节可能比请求的少,长数据要循环读
调试从哪下手
先在命令行验证链路:Windows 上用 netstat -ano 查端口有没有处于 LISTENING 状态,再用 telnet 目标 IP 端口试连通性。防火墙拦截、云服务器安全组没放行、程序只绑了 127.0.0.1,是连不上的三大常见原因。
实际选型建议:要求数据完整、有来有回的选 TCP,比如接口调用、文件传输;丢一两个包无所谓、追求实时的选 UDP,比如音视频、心跳广播。先把基本流程跑通,再考虑多线程和异步模型。