SocketException: Connection refused 主因是服务端未启动或端口占用;readLine()卡死因缺少换行符;多客户端需多线程处理;中文乱码因字符流与字节流编码不一致。

客户端连不上服务器,SocketException: Connection refused 怎么办
绝大多数情况是服务器根本没跑起来,或者端口被占用了。Java 的 Socket 默认连接 localhost:8080,但你的服务端可能监听的是 127.0.0.1:9999,或者压根没调用 ServerSocket.accept() 进入阻塞等待状态。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 先用命令行确认服务端是否真在监听:
netstat -an | grep 9999(macOS/Linux)或netstat -ano | findstr :9999(Windows) - 服务端启动后,别急着运行客户端——加一行
System.out.println("Server started on port 9999");确保初始化完成 - 客户端创建
Socket时,IP 不要硬写"localhost",改用"127.0.0.1",避免 IPv6 解析失败导致超时后才报错 - 防火墙不是主因,但如果你改了非本地 IP(比如
"192.168.1.100"),记得关掉 Windows 防火墙临时测试
BufferedReader.readLine() 卡死、不返回,客户端收不到消息
这是新手最常踩的坑:服务端发消息没换行,readLine() 会一直等 \n 或 \r\n 到来。它不是“收到多少读多少”,而是“必须读到一行才返回”。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 所有
PrintWriter发送消息时,必须调用println(),不能只用print()或write() - 如果服务端用
OutputStream手动写字符串,记得补上os.write("\n".getBytes()); os.flush(); - 不要混用
Scanner和BufferedReader读同一个 socket 输入流——它们内部缓冲区打架,必丢数据 - 调试时,在
readLine()前加日志:System.out.println("About to read...");,能快速区分是卡在网络还是逻辑里
多个客户端连上来,为什么只有第一个能发消息?
因为服务端没做多线程隔离,所有客户端共用一个线程处理输入输出,第二个连接进来时,主线程还卡在第一个客户端的 readLine() 上。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 每次
serverSocket.accept()返回新Socket,立刻丢给新线程处理:new Thread(new ClientHandler(clientSocket)).start(); -
ClientHandler类里,把BufferedReader和PrintWriter都声明为实例变量,别在方法里反复 new —— 流对象不是线程安全的,复用更稳 - 广播消息给所有人?别用静态集合存
PrintWriter,容易并发修改异常;改用CopyOnWriteArrayList<printwriter></printwriter>,它允许遍历时安全添加/删除 - 客户端断开时,
readLine()会返回null,这是唯一可靠的断连信号,别依赖 try-catchIOException来判断——网络抖动也会抛这个异常
中文发过去变成乱码,UTF-8 指定对了也没用
问题不在编码本身,而在字符流和字节流之间没对齐。PrintWriter 默认用平台编码(Windows 是 GBK),即使你构造时传了 "UTF-8",如果底层 OutputStream 没同步设置,照样出错。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 服务端创建
PrintWriter必须这样写:new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true) - 客户端读取也一样:
new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")) - 别信 IDE 控制台显示——它可能用 UTF-8 渲染,但实际终端编码是 GBK;用 telnet 或 nc 测试最真实:
nc 127.0.0.1 9999 - 如果用
DataInputStream/DataOutputStream,就别碰字符编码,它们只认字节;想传字符串,老实用writeUTF()+readUTF()
线程安全和编码对齐这两个点,平时不显眼,一上线就集中爆发。尤其是广播逻辑里混用不同编码的流,查起来特别费时间。











