serversocket.bind()失败主因是端口占用或权限不足;inputstream阻塞因未调用shutdownoutput();accept()后需设超时并检查连接状态;中文乱码源于未统一字符编码。

ServerSocket.bind() 失败:端口被占用或权限不足
启动 ServerSocket 时抛出 java.net.BindException: Address already in use,大概率是端口正被其他进程占着,或者非 root 用户尝试绑定 1024 以下端口。
- 先用
netstat -anp | grep :8080(Linux/macOS)或netstat -ano | findstr :8080(Windows)查端口占用,再用kill -9 PID或任务管理器结束进程 - 开发阶段避开
80、443、22这类敏感端口,改用8080、9090等高位端口 -
ServerSocket构造时传0(如new ServerSocket(0))可让系统自动分配空闲端口,适合测试场景,但需后续调用getLocalPort()获取实际端口号
Socket.getInputStream() 阻塞卡死:没发完数据就关流
TCP 是字节流协议,没有天然消息边界。如果客户端写完数据后不调用 shutdownOutput() 或关闭 Socket,服务端的 InputStream.read() 会一直等——不是 bug,是协议设计如此。
- 客户端发完必须显式调用
socket.shutdownOutput(),告诉对端“我发完了”,服务端才能读到 EOF(-1) - 别依赖
readLine()做粘包处理,它只认\n或\r\n,而 HTTP/JSON/二进制协议往往不用换行分隔 - 更稳妥的做法是约定长度头:先发 4 字节 int 表示 body 长度,再读对应字节数,避免无限阻塞
ServerSocket.accept() 后立即 read() 报 IOException:连接已断
客户端发起 connect() 后瞬间断网、强制 kill、或未完成三次握手就关闭,会导致 accept() 返回一个看似合法实则不可用的 Socket。此时立刻调用 getInputStream().read() 可能直接抛 IOException: Connection reset 或 Broken pipe。
新生代企业网站管理系统是一款基于php+mysql+smarty的免费开源建站系统。整套系统的设计构造,完全考虑大中小企业类网站的功能要求,网站的后台功能强大,管理简捷,支持模板机制,配置中英文双语言版。通过新生代企业网站管理系统,企业建站者可以轻松构建一个企业网站,让企业用户可以更加便捷了解企业的相关信息与动态;方便快捷地发布企业信息、产品等;更可以十分方便的通过管理平台管理企业的站内新闻、产品
- 每次
accept()后,先检查socket.isClosed()和socket.isConnected(),但注意后者只要握手成功就返回 true,不保证后续可用 - 真正安全的做法是:用
setSoTimeout(5000)给 socket 设置读超时,再 try-catch 所有 IO 异常,失败就 close 并 continue 下一轮 accept - 别在主线程里长期 hold 住
accept()返回的 socket,应尽快丢给线程池处理,否则新连接会被堵住
中文乱码:Socket 默认不处理字符编码
Socket 和 ServerSocket 传输的是原始字节,BufferedReader.readLine() 或 PrintWriter.println() 用的是平台默认编码(Windows 是 GBK,Linux/macOS 是 UTF-8),跨平台通信极易乱码。
立即学习“Java免费学习笔记(深入)”;
- 客户端和服务端必须显式指定编码,比如都用
new OutputStreamWriter(socket.getOutputStream(), "UTF-8") - 别用
DataInputStream.readLine()(已废弃),它硬编码 ISO-8859-1,读中文必错 - 如果走 JSON 协议,建议直接用
InputStream读字节,再用new String(bytes, StandardCharsets.UTF_8)解码,绕过字符流陷阱








