java socket编程无标准模板,分tcp服务端、tcp客户端、udp三类路径;tcp服务端必须阻塞调用accept(),客户端需捕获连接异常并设超时,流操作须配对且注意关闭顺序。

Java Socket编程没有“标准步骤”模板,只有按通信角色和协议类型区分的三类基础路径:TCP服务端、TCP客户端、UDP通信。照搬“四步流程”容易在阻塞、流关闭、线程模型上出问题。
TCP服务端必须用ServerSocket.accept()阻塞等待连接
这一步不是可选操作,而是协议强制行为——TCP三次握手完成后,accept()才返回一个已建立连接的Socket实例。如果跳过或试图非阻塞调用(比如用setSoTimeout(0)),会直接抛SocketTimeoutException或陷入空轮询。
- 监听端口时避开 0–1023 系统保留端口,推荐从
8080、9000起始 -
accept()返回后,必须为每个客户端分配独立线程或交由线程池处理,否则后续连接会被挂起 - 不要在
accept()前对ServerSocket调用close(),否则抛SocketException: socket closed
TCP客户端连接失败常见于Socket构造时未捕获IOException
创建 Socket("localhost", 8080) 瞬间就可能失败:目标端口无服务、防火墙拦截、IP不可达、DNS解析超时。这个异常必须显式处理,不能只靠 try-with-resources 后续逻辑兜底。
- 连接超时默认无限等待,建议显式设置:
socket.connect(new InetSocketAddress("localhost", 8080), 5000) - 连接成功后立即检查
socket.isConnected()和!socket.isClosed(),避免后续流操作报SocketException: connection reset - 别在连接未完成时就调
getInputStream(),否则可能阻塞或抛IllegalStateException
getInputStream() 和 getOutputStream() 必须配对使用且注意关闭顺序
这两个方法返回的流与底层 Socket 绑定,关闭流不等于关闭 Socket,但关闭 Socket 会自动关闭关联流。实际开发中,多数资源泄漏和 Broken pipe 错误都源于关闭时机混乱。
- 推荐用
try-with-resources包裹InputStream和OutputStream,但需确保 Socket 实例本身也在外层 try 中管理 - 不要先
shutdownOutput()再读响应——这会触发 TCP 半关闭,服务端可能提前断开输入流 - 若用
BufferedReader.readLine(),注意它依赖换行符;服务端没写"\n"就flush(),客户端会永远阻塞在readLine()
真正难的不是写出能连通的代码,而是让连接在高并发、网络抖动、异常中断下仍可预测地释放资源。很多问题只在压测或长连接场景暴露,比如 ServerSocket 的 backlog 参数设太小导致连接被内核丢弃,或者 Socket.setSoTimeout() 没覆盖所有读写路径。这些细节不写进日志,就只能靠抓包定位。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











