ServerSocket.accept()阻塞但客户端连不上,本质是服务端未真正监听:端口被占、绑定地址错误(如仅127.0.0.1)、防火墙拦截或AP隔离。

为什么 ServerSocket.accept() 会一直阻塞,但客户端连不上?
本质是服务端没真正“监听”到请求,常见于绑定地址或端口被占用。不是代码写错了,而是网络环境没配对。
-
ServerSocket构造时传0端口会让系统自动分配,但客户端必须知道实际端口号——别硬编码8080就以为能通 - 用
new ServerSocket(8080)前,先执行netstat -an | grep 8080(macOS/Linux)或netstat -ano | findstr :8080(Windows),确认端口空闲 - 局域网内要连通,服务端
bind不能只绑127.0.0.1;改用new ServerSocket(8080, 50, InetAddress.getByName("0.0.0.0"))或直接无参构造(默认监听所有接口) - Windows 防火墙、Mac 的“防火墙”设置、甚至某些路由器的 AP 隔离功能,都会让
accept()看不到跨设备连接——先关掉防火墙测通断
多个客户端连上来后,消息只发给最后一个?
典型误区:把 PrintWriter 或 OutputStream 存成单例变量反复覆盖。每个客户端连接对应一个独立的 Socket,也必须有独立的输出通道。
- 不要在主线程里复用同一个
PrintWriter;每次accept()后,立刻为新Socket创建专属的PrintWriter和BufferedReader - 用
ArrayList<printwriter></printwriter>或CopyOnWriteArrayList<printwriter></printwriter>缓存所有客户端的输出流,广播时遍历发送,别漏掉自己加进去的那个 - 注意
PrintWriter默认不自动 flush,要么构造时开true参数:new PrintWriter(socket.getOutputStream(), true),要么每次println()后手动flush() - 如果用
BufferedWriter,记得换行符必须是\n(不是\r\n),否则 Java 客户端的readLine()读不到完整消息
Socket 关闭后,另一端还收得到“空消息”?
这是 TCP 半关闭行为导致的假象:一端调用 close(),对方 read() 返回 -1,但若没检查返回值就继续 readLine(),就会得到 null——这不是消息,是流结束信号。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 所有读取逻辑必须包裹在
while ((line = reader.readLine()) != null)中,而不是while (true) { line = reader.readLine(); ... } - 别依赖
socket.isClosed()判断是否可读;它只反映本端状态,对端断连后该方法仍返回false - 客户端退出时,建议先发一条
"BYE"协议消息,再关流;服务端收到后主动移除对应PrintWriter,避免后续广播误触已失效流 - 服务端用
try-with-resources包裹Socket不够——Socket关闭会同时关掉其InputStream和OutputStream,但广播循环可能还在用已关闭的PrintWriter,得加if (pw.checkError())提前剔除
中文发过去变成乱码,但英文正常?
根本原因:没统一字符集。Java 默认用平台编码(Windows 是 GBK,Mac/Linux 是 UTF-8),而聊天室必须强制约定一种编码,且两端一致。
立即学习“Java免费学习笔记(深入)”;
- 创建
InputStreamReader和OutputStreamWriter时,**必须显式指定"UTF-8"**:new InputStreamReader(socket.getInputStream(), "UTF-8") - 别用
Scanner直接包装Socket.getInputStream()——它底层用平台默认编码,且不支持指定 charset - 如果用
DataInputStream/DataOutputStream,它们只认字节,不处理编码;中文得先"你好".getBytes(StandardCharsets.UTF_8)再发,接收端再用同样 Charset 解码 - 测试时别只在 IDE 控制台看输出:IDEA 默认 UTF-8,但 Windows CMD 是 GBK,容易误判;用两个真实终端(如 Terminal + PowerShell)或写个简单 Swing 客户端验证
局域网聊天室看着简单,但每条消息背后都卡着地址绑定、流生命周期、编码对齐、异常清理四个硬点。少盯一个,就卡在“明明连上了却收不到”这种问题上。


















