前言网络编程是 Java 后端开发、中间件、IM 聊天、爬虫、接口服务的底层基础不管是 Spring Web、Netty、还是简单 HTTP 接口底层全部依赖 Java 原生网络 API。 很多初学者学习网络时存在痛点只懂理论、代码残缺、分不清 BIO 与 NIO、不会处理超时 / 资源泄漏 / 重试异常。 本文循序渐进基础概念→TCP 阻塞通信→UDP 无连接通信→HTTP 两种客户端→NIO 非阻塞服务→生产级最佳实践所有代码本地可直接运行覆盖面试高频考点零基础也能看懂。一、网络编程前置基础IP、端口、URL、URI1.1 InetAddress操作本机 / 远程 IP 地址核心作用获取主机名、IP、检测主机连通性底层封装 DNS 解析。java运行import java.net.InetAddress; import java.net.UnknownHostException; public class IPTest { public static void main(String[] args) { try { // 获取本机IP与主机名 InetAddress local InetAddress.getLocalHost(); System.out.println(本机主机名 local.getHostName()); System.out.println(本机IP local.getHostAddress()); // 解析域名IP InetAddress target InetAddress.getByName(www.baidu.com); System.out.println(百度IP target.getHostAddress()); // 连通性检测超时5秒 boolean reach target.isReachable(5000); System.out.println(是否能连通 reach); } catch (Exception e) { e.printStackTrace(); } } }1.2 URL 与 URI 核心区分URI统一资源标识符只标识资源不包含访问协议URL统一资源定位符属于 URI 子集包含协议、主机、端口、路径、参数、锚点可直接访问网络资源。java运行import java.net.URL; import java.net.URI; public class UrlUriTest { public static void main(String args[]) throws Exception { URL url new URL(https://blog.csdn.net:8080/article?id123#top); System.out.println(协议 url.getProtocol()); System.out.println(主机 url.getHost()); System.out.println(端口 url.getPort()); System.out.println(请求参数 url.getQuery()); URI baseUri new URI(https://blog.csdn.net); URI relative new URI(/java); URI full baseUri.resolve(relative); System.out.println(拼接后URI full); } }二、BIO 阻塞 TCP 通信Socket/ServerSocketTCP 是面向连接、可靠、字节流传输协议分客户端、服务端服务端多客户端需搭配线程池。2.1 TCP 客户端代码java运行import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TcpClient { public static void main(String[] args) { String host 127.0.0.1; int port 8080; try (Socket socket new Socket(host, port); BufferedReader in new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out new PrintWriter(socket.getOutputStream(), true); BufferedReader console new BufferedReader(new InputStreamReader(System.in))) { // 新开线程持续读取服务器推送消息 new Thread(() - { String resp; try { while ((resp in.readLine()) ! null) { System.out.println(服务端返回 resp); } } catch (Exception e) { System.out.println(连接断开); } }).start(); // 控制台输入发送消息 String input; while ((input console.readLine()) ! null) { out.println(input); if (exit.equals(input)) break; } } catch (Exception e) { e.printStackTrace(); } } }2.2 TCP 服务端线程池处理多客户端java运行import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TcpServer { private static final int PORT 8080; private static final ExecutorService pool Executors.newFixedThreadPool(10); public static void main(String[] args) throws Exception { try (ServerSocket server new ServerSocket(PORT)) { System.out.println(TCP服务启动监听8080端口); while (true) { Socket client server.accept(); System.out.println(新客户端接入 client.getRemoteSocketAddress()); pool.execute(new ClientTask(client)); } } finally { pool.shutdown(); } } static class ClientTask implements Runnable { private Socket socket; public ClientTask(Socket socket) {this.socket socket;} Override public void run() { try (BufferedReader in new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out new PrintWriter(socket.getOutputStream(), true)) { String msg; while ((msg in.readLine()) ! null) { System.out.println(收到客户端消息 msg); out.println(服务已收到 msg.toUpperCase()); if (exit.equalsIgnoreCase(msg)) break; } } catch (Exception e) { e.printStackTrace(); } finally { try {socket.close();} catch (Exception e) {} } } } }TCP 核心特点总结三次握手建立连接四次挥手断开可靠传输丢失数据包自动重传面向字节流无数据包边界BIO 模式一线程处理一个连接并发上万连接会出现线程爆炸。三、UDP 无连接数据报通信DatagramSocketUDP 无连接、不可靠、基于数据包传输适合直播、语音、心跳包等允许少量丢包场景收发独立无需提前建立连接。3.1 UDP 客户端java运行import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UdpClient { public static void main(String[] args) throws Exception { DatagramSocket socket new DatagramSocket(); String data UDP测试消息; byte[] sendBuf data.getBytes(); InetAddress server InetAddress.getByName(127.0.0.1); DatagramPacket sendPkg new DatagramPacket(sendBuf, sendBuf.length, server, 9090); socket.send(sendPkg); // 接收服务端回包 byte[] recBuf new byte[1024]; DatagramPacket recPkg new DatagramPacket(recBuf, recBuf.length); socket.receive(recPkg); String res new String(recPkg, 0, recPkg.getLength()); System.out.println(服务端回复 res); socket.close(); } }3.2 UDP 服务端java运行import java.net.DatagramPacket; import java.net.DatagramSocket; public class UdpServer { private static final int PORT 9090; private static final int BUF_SIZE 1024; public static void main(String[] args) throws Exception { DatagramSocket socket new DatagramSocket(PORT); System.out.println(UDP服务启动); byte[] buf new byte[BUF_SIZE]; while (true) { DatagramPacket pkg new DatagramPacket(buf, buf.length); socket.receive(pkg); String msg new String(pkg.getData(), 0, pkg.getLength()); System.out.println(收到数据 msg); // 原路返回响应包 String resp 服务应答 msg; byte[] respBuf resp.getBytes(); DatagramPacket respPkg new DatagramPacket(respBuf, respBuf.length, pkg.getAddress(), pkg.getPort()); socket.send(respPkg); } } }UDP 核心特点无需建立连接发送消息不用等待握手无重传机制数据包可能丢失、乱序单包最大 64KB超大文件不适合 UDP资源开销极低并发性能优于 BIO。四、Java HTTP 客户端两种实现方式4.1 老式 HttpURLConnectionJava8 通用适配低版本 JDK适合简单 GET/POST 请求java运行import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpOldDemo { public static void main(String[] args) throws Exception { URL url new URL(https://jsonplaceholder.typicode.com/posts/1); HttpURLConnection conn (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setRequestProperty(User-Agent, Java-Client); int code conn.getResponseCode(); if (code 200) { BufferedReader br new BufferedReader(new InputStreamReader(conn.getInputStream())); StringBuilder sb new StringBuilder(); String line; while ((line br.readLine()) ! null) { sb.append(line); } System.out.println(响应内容 sb); br.close(); } conn.disconnect(); } }4.2 Java11 全新 HttpClient推荐原生异步、同步支持API 简洁生产新项目首选GET 示例java运行import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class HttpGetDemo { public static void main(String[] args) throws Exception { HttpClient client HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(5)) .build(); HttpRequest req HttpRequest.newBuilder() .uri(URI.create(https://jsonplaceholder.typicode.com/posts/1)) .header(User-Agent, Java11-HttpClient) .GET() .build(); HttpResponseString resp client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(状态码 resp.statusCode()); System.out.println(返回JSON resp.body()); } }POST JSON 示例java运行import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class HttpPostDemo { public static void main(String[] args) throws Exception { HttpClient client HttpClient.newHttpClient(); String json { title:测试, body:Java网络编程POST, userId:1 } ; HttpRequest req HttpRequest.newBuilder() .uri(URI.create(https://jsonplaceholder.typicode.com/posts)) .header(Content-Type, application/json) .POST(HttpRequest.BodyPublishers.ofString(json)) .build(); HttpResponseString res client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.body()); } }五、NIO 非阻塞网络编程BIO 并发痛点解决方案BIO 一个连接占用一个线程上万连接直接 OOMNIO 单线程通过 Selector 多路复用器管理成千上百连接是 Netty 底层核心。NIO TCP 服务端完整代码java运行import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.Socket; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NioServerDemo { private static final int PORT 8080; private static final int BUF 1024; public static void main(String[] args) throws IOException { Selector selector Selector.open(); ServerSocketChannel server ServerSocketChannel.open(); server.configureBlocking(false); server.bind(new InetSocketAddress(PORT)); server.register(selector, SelectionKey.OP_ACCEPT); System.out.println(NIO非阻塞服务启动); while (true) { selector.select(); SetSelectionKey keys selector.selectedKeys(); IteratorSelectionKey it keys.iterator(); while (it.hasNext()) { SelectionKey key it.next(); it.remove(); if (key.isAcceptable()) { acceptHandler(key, selector); } else if (key.isReadable()) { readHandler(key); } } } } // 处理客户端接入 private static void acceptHandler(SelectionKey key, Selector selector) throws IOException { ServerSocketChannel server (ServerSocketChannel) key.channel(); SocketChannel client server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); System.out.println(客户端连接成功); } // 读取客户端数据 private static void readHandler(SelectionKey key) throws IOException { SocketChannel channel (SocketChannel) key.channel(); ByteBuffer buffer ByteBuffer.allocate(BUF); int len channel.read(buffer); if (len -1) { channel.close(); return; } buffer.flip(); String msg new String(buffer.array(), 0, buffer.limit()); System.out.println(收到 msg); buffer.rewind(); channel.write(buffer); } }NIO 三大核心组件Channel 通道替代 Socket 流双向读写Buffer 缓冲区数据读写载体Selector 选择器多路复用监听所有 Channel 事件连接、读、写。六、Java 网络编程生产级最佳实践面试高频6.1 资源必须自动关闭try-with-resources错误写法手动 close 容易遗漏出现连接泄漏 推荐写法流、Socket、HttpClient 自动释放资源java运行// 标准安全写法 try (Socket socket new Socket(127.0.0.1,8080); BufferedReader br new BufferedReader(new InputStreamReader(socket.getInputStream()))){ // 业务逻辑 } catch (Exception e) { e.printStackTrace(); }6.2 强制设置超时时间连接超时、读取超时缺一不可避免死线程卡死服务java运行Socket socket new Socket(); socket.connect(new InetSocketAddress(127.0.0.1,8080),5000); socket.setSoTimeout(10000);6.3 网络异常分层处理 指数退避重试区分连接失败、读取超时、IO 异常重试不能无限循环使用指数休眠java运行public void connectWithRetry() { int maxRetry 3; int count 0; while (count maxRetry) { try { // 网络请求逻辑 break; } catch (java.net.ConnectException e) { count; System.out.println(连接失败第count次重试); try { Thread.sleep(count * 1000); } catch (InterruptedException ie) {} } catch (java.net.SocketTimeoutException e) { System.out.println(读取超时放弃重试); break; } } }6.4 多并发网络请求使用线程池禁止循环 new Thread频繁创建线程造成 GC 抖动java运行ExecutorService pool Executors.newCachedThreadPool(); pool.submit(() - { // 异步网络请求 });七、全文知识点总结基础层InetAddress、URL、URI 负责网络地址解析同步阻塞BIO TCP 适合低并发小型工具无连接传输UDP 适合直播、心跳、轻量推送HTTP 请求Java8 用 HttpURLConnectionJava11 优先 HttpClient高并发底层NIO 多路复用Netty 底层实现 6 生产规范超时、自动关闭资源、异常重试、线程池。结尾本文覆盖 Java 网络编程全部基础模块所有代码均可直接复制运行适合期末实验、面试突击、后端入门。后续会更新 Netty 框架实战如果你在调试 Socket、NIO 代码遇到报错可以评论留言逐一解答。