Java 网络编程全解:TCP、UDP、HTTP、WebSocket

Java 网络编程核心是基于 Socket 实现传输层通信(TCP/UDP)基于标准库 / 框架实现应用层协议(HTTP/WebSocket) ,覆盖基础通信、生产环境高可用、并发、异常处理、资源释放等全场景。

一、核心基础概念

  1. TCP:面向连接、可靠、有序、字节流传输(如:文件传输、接口调用)
  2. UDP:无连接、不可靠、快速、数据报传输(如:直播、实时消息)
  3. HTTP:应用层协议,基于 TCP,短连接 / 长连接(Web 接口、网页)
  4. WebSocket:基于 TCP 的全双工长连接,解决 HTTP 轮询弊端(实时通信)
  5. Socket :Java 网络编程的基石,是IP + 端口 的抽象,分为:
    • ServerSocket:服务端,监听端口等待连接
    • Socket:客户端,主动发起连接

代码概括:

二、传输层编程:TCP(生产级)

基础原理

  • 三次握手建立连接,四次挥手断开
  • 可靠传输:超时重传、拥塞控制、顺序保证
  • 适合:需要数据不丢失、不乱序的场景

生产级 TCP 服务端(线程池 + 心跳 + 优雅关闭)

核心优化

  1. 线程池异步处理客户端,避免单线程阻塞
  2. 心跳机制检测死连接
  3. 优雅关闭:释放端口、关闭线程池、中断线程
  4. 全局异常捕获 + 日志
  5. 配置化端口、超时时间
java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 生产级 TCP 服务端
 */
public class TcpServer {
    private static final Logger log = LoggerFactory.getLogger(TcpServer.class);
    // 配置化参数(可抽取到配置文件)
    private static final int PORT = 9999;
    private static final int SO_TIMEOUT = 30000; // 30秒无心跳断开
    private static final int CORE_POOL_SIZE = 10;

    private final ExecutorService threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
    private ServerSocket serverSocket;
    private volatile boolean isRunning = true;

    public static void main(String[] args) {
        new TcpServer().start();
    }

    /**
     * 启动服务端
     */
    public void start() {
        try {
            serverSocket = new ServerSocket(PORT);
            log.info("TCP 服务端启动成功,端口:{}", PORT);

            // 注册优雅关闭钩子
            Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));

            while (isRunning) {
                // 阻塞等待客户端连接
                Socket clientSocket = serverSocket.accept();
                log.info("客户端连接成功:{}:{}", clientSocket.getInetAddress(), clientSocket.getPort());

                // 线程池处理客户端请求
                threadPool.execute(new ClientHandler(clientSocket));
            }
        } catch (Exception e) {
            if (isRunning) {
                log.error("TCP 服务端异常", e);
            }
        }
    }

    /**
     * 优雅关闭
     */
    public void shutdown() {
        try {
            isRunning = false;
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
            threadPool.shutdown();
            if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
                threadPool.shutdownNow();
            }
            log.info("TCP 服务端已优雅关闭");
        } catch (Exception e) {
            log.error("服务端关闭异常", e);
        }
    }

    /**
     * 客户端处理器(生产级:心跳、异常处理、资源释放)
     */
    private static class ClientHandler implements Runnable {
        private final Socket socket;
        private BufferedReader reader;
        private BufferedWriter writer;

        public ClientHandler(Socket socket) {
            this.socket = socket;
            try {
                socket.setSoTimeout(SO_TIMEOUT); // 读超时(心跳检测)
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            } catch (Exception e) {
                close();
            }
        }

        @Override
        public void run() {
            try {
                String msg;
                while ((msg = reader.readLine()) != null) {
                    log.info("收到客户端消息:{}", msg);

                    // 心跳包处理
                    if ("heartbeat".equals(msg)) {
                        sendMsg("heartbeat_ack");
                        continue;
                    }

                    // 业务消息处理
                    String resp = "服务端已接收:" + msg;
                    sendMsg(resp);
                }
            } catch (Exception e) {
                log.warn("客户端连接异常:{}", e.getMessage());
            } finally {
                close();
            }
        }

        /**
         * 发送消息
         */
        private void sendMsg(String msg) throws IOException {
            writer.write(msg + "\n");
            writer.flush();
        }

        /**
         * 统一释放资源
         */
        private void close() {
            try {
                if (reader != null) reader.close();
                if (writer != null) writer.close();
                if (socket != null && !socket.isClosed()) socket.close();
                log.info("客户端连接已关闭:{}:{}", socket.getInetAddress(), socket.getPort());
            } catch (Exception e) {
                log.error("资源释放异常", e);
            }
        }
    }
}

生产级 TCP 客户端(重连 + 心跳 + 异步发送)

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 生产级 TCP 客户端(自动重连+心跳)
 */
public class TcpClient {
    private static final Logger log = LoggerFactory.getLogger(TcpClient.class);
    private static final String SERVER_HOST = "127.0.0.1";
    private static final int SERVER_PORT = 9999;
    private static final int HEARTBEAT_INTERVAL = 5; // 5秒心跳
    private static final int RECONNECT_INTERVAL = 3; // 3秒重连

    private Socket socket;
    private BufferedReader reader;
    private BufferedWriter writer;
    private volatile boolean isConnected = false;
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public static void main(String[] args) {
        TcpClient client = new TcpClient();
        client.connect();
        // 测试发送消息
        client.sendMsg("Hello TCP Server");
    }

    /**
     * 建立连接(失败自动重连)
     */
    public void connect() {
        while (!isConnected) {
            try {
                socket = new Socket(SERVER_HOST, SERVER_PORT);
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                isConnected = true;
                log.info("连接服务端成功");

                // 启动心跳
                startHeartbeat();
                // 监听服务端消息
                new Thread(this::listenServerMsg).start();
            } catch (Exception e) {
                log.error("连接失败,{}秒后重试...", RECONNECT_INTERVAL);
                try {
                    TimeUnit.SECONDS.sleep(RECONNECT_INTERVAL);
                } catch (InterruptedException ignored) {}
            }
        }
    }

    /**
     * 心跳机制
     */
    private void startHeartbeat() {
        scheduler.scheduleAtFixedRate(() -> {
            try {
                if (isConnected) {
                    sendMsg("heartbeat");
                    log.debug("发送心跳包");
                }
            } catch (Exception e) {
                log.error("心跳异常,开始重连");
                disconnect();
                connect();
            }
        }, 0, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
    }

    /**
     * 监听服务端消息
     */
    private void listenServerMsg() {
        try {
            String msg;
            while ((msg = reader.readLine()) != null) {
                log.info("收到服务端消息:{}", msg);
            }
        } catch (Exception e) {
            log.warn("与服务端断开连接");
            disconnect();
            connect();
        }
    }

    /**
     * 发送消息(线程安全)
     */
    public synchronized void sendMsg(String msg) {
        if (!isConnected) {
            log.warn("未连接服务端,消息发送失败:{}", msg);
            return;
        }
        try {
            writer.write(msg + "\n");
            writer.flush();
        } catch (Exception e) {
            log.error("消息发送异常", e);
            disconnect();
            connect();
        }
    }

    /**
     * 断开连接
     */
    private void disconnect() {
        isConnected = false;
        try {
            if (reader != null) reader.close();
            if (writer != null) writer.close();
            if (socket != null) socket.close();
        } catch (Exception ignored) {}
    }
}

三、传输层编程:UDP(生产级)

基础原理

  • 无连接,直接发送数据报
  • 速度快,不保证可靠
  • 适合:实时性要求高、可容忍少量丢包的场景

生产级 UDP 服务端 + 客户端

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 生产级 UDP(服务端+客户端合一)
 */
public class UdpServerClient {
    private static final Logger log = LoggerFactory.getLogger(UdpServerClient.class);
    private static final int PORT = 9998;
    private static final int BUFFER_SIZE = 1024;
    private final ExecutorService threadPool = Executors.newSingleThreadExecutor();

    public static void main(String[] args) {
        UdpServerClient udp = new UdpServerClient();
        udp.startServer();
        udp.sendClientMsg("127.0.0.1", "Hello UDP Server");
    }

    // ==================== UDP 服务端 ====================
    public void startServer() {
        threadPool.execute(() -> {
            try (DatagramSocket socket = new DatagramSocket(PORT)) {
                log.info("UDP 服务端启动,端口:{}", PORT);
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true) {
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    socket.receive(packet); // 阻塞接收

                    String msg = new String(packet.getData(), 0, packet.getLength());
                    log.info("收到UDP消息:{} 来自:{}:{}",
                            msg, packet.getAddress(), packet.getPort());

                    // 回写消息
                    String resp = "UDP 已接收:" + msg;
                    sendUdpMsg(socket, packet.getAddress(), packet.getPort(), resp);
                }
            } catch (Exception e) {
                log.error("UDP 服务端异常", e);
            }
        });
    }

    // ==================== UDP 客户端发送 ====================
    public void sendClientMsg(String host, String msg) {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress address = InetAddress.getByName(host);
            sendUdpMsg(socket, address, PORT, msg);
            log.info("UDP 客户端发送消息:{}", msg);
        } catch (Exception e) {
            log.error("UDP 客户端发送异常", e);
        }
    }

    /**
     * 统一发送 UDP 消息
     */
    private void sendUdpMsg(DatagramSocket socket, InetAddress addr, int port, String msg) throws Exception {
        byte[] data = msg.getBytes();
        DatagramPacket packet = new DatagramPacket(data, data.length, addr, port);
        socket.send(packet);
    }
}

四、应用层编程:HTTP(生产级)

Java 生产环境绝不使用原生 HttpURLConnection,推荐两款标准框架:

  1. OkHttp:轻量、稳定、Android / 后端通用
  2. RestTemplate:Spring 生态标准(微服务首选)

1. OkHttp 生产级 HTTP 工具类

依赖

java 复制代码
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>

生产级代码(连接池、超时、重试、单例):

java 复制代码
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;

/**
 * 生产级 OkHttp 工具类(单例+连接池)
 */
public class OkHttpUtil {
    private static final Logger log = LoggerFactory.getLogger(OkHttpUtil.class);
    private static final OkHttpClient CLIENT;
    private static final int MAX_IDLE_CONNECTIONS = 20;
    private static final long KEEP_ALIVE_DURATION = 5L;

    // 单例 OkHttpClient(关键:OkHttp 必须单例,复用连接池)
    static {
        CLIENT = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.MINUTES))
                .retryOnConnectionFailure(true) // 自动重试
                .build();
    }

    private OkHttpUtil() {}

    /**
     * GET 请求
     */
    public static String get(String url) throws Exception {
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Content-Type", "application/json")
                .build();

        try (Response response = CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new Exception("HTTP 请求失败,状态码:" + response.code());
            }
            return response.body().string();
        }
    }

    /**
     * POST JSON 请求
     */
    public static String postJson(String url, String json) throws Exception {
        RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        try (Response response = CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new Exception("HTTP POST 失败,状态码:" + response.code());
            }
            return response.body().string();
        }
    }
}

2. Spring RestTemplate 生产级配置

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * Spring 生产级 RestTemplate 配置
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(10000);
        // 生产环境可替换为 OkHttp 工厂,性能更强
        return factory;
    }
}

五、应用层编程:WebSocket(生产级)

基础原理

  • 基于 TCP,全双工长连接
  • 一次握手,永久通信,服务端可主动推送消息
  • 适合:聊天、实时通知、大屏数据

Spring Boot 生产级 WebSocket

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

生产级代码(集群可配合 Redis 广播):

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 生产级 WebSocket 服务端
 */
@Component
@ServerEndpoint("/ws/server")
public class WebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    // 在线连接数(线程安全)
    private static final AtomicInteger ONLINE_COUNT = new AtomicInteger(0);
    // 客户端集合(线程安全)
    private static final CopyOnWriteArraySet<WebSocketServer> WEB_SOCKET_SET = new CopyOnWriteArraySet<>();

    private Session session;

    /**
     * 连接建立成功
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        WEB_SOCKET_SET.add(this);
        ONLINE_COUNT.incrementAndGet();
        log.info("新连接加入,当前在线:{}", ONLINE_COUNT.get());
        sendMessage("连接成功");
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        WEB_SOCKET_SET.remove(this);
        ONLINE_COUNT.decrementAndGet();
        log.info("连接关闭,当前在线:{}", ONLINE_COUNT.get());
    }

    /**
     * 收到客户端消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到消息:{}", message);
        // 群发消息
        sendToAll("服务端广播:" + message);
    }

    /**
     * 异常处理
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket 异常", error);
    }

    /**
     * 发送消息
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("消息发送失败", e);
        }
    }

    /**
     * 群发消息(生产常用)
     */
    public static void sendToAll(String message) {
        for (WebSocketServer ws : WEB_SOCKET_SET) {
            ws.sendMessage(message);
        }
    }
}

启用 WebSocket

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.socket.config.annotation.EnableWebSocket;

@SpringBootApplication
@EnableWebSocket // 开启 WebSocket
public class NettyApplication {
    public static void main(String[] args) {
        SpringApplication.run(NettyApplication.class, args);
    }
}

六、生产环境核心最佳实践(必看)

  1. Socket 必须单例 / 池化
    • TCP 客户端、OkHttp、RestTemplate 禁止频繁创建对象,必须复用连接池
  2. 超时强制设置
    • 连接超时、读超时、写超时,避免线程无限阻塞
  3. 优雅关闭
    • shutdownHook 释放端口、线程池、Socket,防止端口占用
  4. 心跳机制
    • TCP/WebSocket 必须加心跳,检测死连接,释放资源
  5. 线程池替代多线程
    • 禁止为每个客户端创建新线程,用线程池控制并发
  6. 异常全覆盖
    • IO 异常、连接异常、超时异常必须捕获,不能直接抛出
  7. 生产禁用原生 Socket 高并发场景
    • 高并发用 Netty(NIO 框架),性能提升 10~100 倍

由以上可总结出:

  1. 传输层:TCP 可靠(生产用线程池 + 心跳),UDP 快速(实时场景)
  2. 应用层:HTTP 用 OkHttp/RestTemplate,WebSocket 用 Spring 封装
  3. 生产核心:连接池、超时、优雅关闭、心跳、异常处理
  4. 高并发方案 :原生 Socket 仅适合小并发,高并发必须用 Netty

概念概括

一 Java 网络编程本质就是两层

  1. 传输层 (TCP、UDP)
    • 基于 Socket 编程
    • 自己定义报文格式、粘包拆包、心跳、重连
  2. 应用层 (HTTP、HTTPS、WebSocket)
    • 基于 TCP 封装好的协议
    • 不用关心底层连接,只关心请求 / 响应

二、TCP、UDP、HTTP、WebSocket 核心区别对比表

对比项 TCP UDP HTTP WebSocket
连接方式 面向连接(三次握手) 无连接 基于 TCP,短 / 长连接 基于 TCP,全双工长连接
可靠性 可靠,不丢包、不乱序 不可靠,可能丢包、乱序 可靠(依赖 TCP) 可靠(依赖 TCP)
传输方式 字节流 数据报 请求 - 响应模型 全双工,双向主动推送
开销 高(握手、确认、重传) 很高(Header 大) 中等(握手一次,后续帧很小)
速度 较慢 极快
消息边界 无边界 → 粘包拆包问题 有边界 → 不会粘包 协议自带边界 帧结构,自带边界
服务端推送 需自己实现 需自己实现 不能主动推送 支持主动推送
典型用途 文件传输、IM、支付、长连接 直播、语音、游戏、DNS 接口、网页、RESTful 聊天、大屏、实时通知、物联网

1. TCP(Transmission Control Protocol)

特点

  • 面向连接,可靠传输
  • 有序、重传、流量控制、拥塞控制
  • 字节流传输,没有消息边界
  • 适合对数据完整性要求高的场景

生产注意事项(非常重要)

  1. 必须处理粘包 / 拆包 TCP 是流,发送 2 次数据可能被合并成 1 次,或 1 次被拆成多段。解决方案:
    • 固定长度
    • 分隔符(\n、\r\n)
    • 长度域 + 报文体(生产标准方案)
  2. 必须设置 SO_TIMEOUT不设置会导致线程永久阻塞,OOM 或线程耗尽
  3. 禁止每次 new Socket必须复用连接、使用连接池
  4. 必须心跳保活NAT 超时、防火墙会静默断开连接,应用层无感知
  5. 必须优雅关闭close () 要放在 finally,避免端口 TIME_WAIT 堆积
  6. 高并发不能用 BIO并发 > 100 必须用 NIO / Netty,否则线程爆炸

2. UDP(User Datagram Protocol)

特点

  • 无连接,不握手,直接发
  • 数据报模式,自带消息边界
  • 速度极快,开销极小
  • 不保证到达、顺序、重复

生产注意事项

  1. 不适合支付、交易、重要指令丢包就没了
  2. 适合实时性 > 可靠性直播、实时游戏、实时监控
  3. 无需处理粘包一个 DatagramPacket 就是一个完整包
  4. 可以自己实现简单可靠机制序号 + 确认 + 重传(RTP 就是这么干的)
  5. 包大小不要超过 MTU一般 ≤ 1472 字节,否则会被 IP 层分片,更容易丢包

3. HTTP(HyperText Transfer Protocol)

特点

  • 应用层协议,基于 TCP
  • 请求 - 响应模型:客户端问,服务端答
  • 无状态(需要 Cookie / Token)
  • 1.1 支持长连接,2.0 多路复用
  • 文本协议,可读性强

生产注意事项

  1. 不能服务端主动推送只能轮询、长轮询,效率低
  2. Header 开销大尤其大量小请求,浪费严重
  3. 必须使用连接池原生 HttpURLConnection 坑多,生产用 OkHttp / RestTemplate
  4. 超时三要素必须设置连接超时、读取超时、写入超时
  5. 重试要谨慎读接口可以重试,写接口(POST/PUT)必须保证幂等
  6. HTTPS 必须使用明文传输极易被抓包篡改

4. WebSocket

特点

  • 基于 TCP,在 HTTP 握手升级而来
  • 全双工:客户端 ↔ 服务端 随时发
  • 一次握手,永久通道
  • 数据帧很小,开销极低
  • 服务端可以主动推送

生产注意事项

  1. 必须心跳代理、防火墙会断开空闲连接
  2. 集群环境要做会话共享多实例部署时,用 Redis 广播 / STOMP 消息队列
  3. 注意内存泄漏Session 要及时清理,关闭连接必须移除集合
  4. 避免大文件传输不是设计用来传文件的
  5. 鉴权要在握手阶段做不要连接建立后再鉴权

四、它们之间的关系(一句话串起来)

  1. HTTP 是跑在 TCP 上的应用协议
  2. WebSocket 也是跑在 TCP 上,先用 HTTP 握手,再升级成双工通道
  3. TCP/UDP 是底层传输,你要自己定义协议
  4. HTTP/WebSocket 是现成协议,开箱即用

五、生产中怎么选择?(最实用)

  • 业务接口、微服务调用HTTP/HTTPS
  • IM、实时通知、大屏WebSocket
  • 自定义长连接、网关、物联网TCP(Netty)
  • 直播、语音、实时游戏UDP(可加可靠层)
  • DNS、心跳探测UDP
相关推荐
可以简单点2 小时前
分析一个线程日志工具类
java·springboot
jinanwuhuaguo2 小时前
OpenClaw、Agent、Skill、MCP 深度解读与区分分析
网络·人工智能·网络协议·rpc·openclaw
EvenBoy2 小时前
IDEA中使用Claude Code
java·ide·intellij-idea
小小马喽_Thendras2 小时前
ScheduledExecutorService 和Timer的区别
java·开发语言
liulilittle2 小时前
静态隧道 UDP 限制与绕过:以 DMIT 机房为例
网络·网络协议·udp
小江的记录本2 小时前
【Swagger】Swagger系统性知识体系全方位结构化总结
java·前端·后端·python·mysql·spring·docker
空太Jun2 小时前
Spring Security 自定义数据库认证(初尝试)
java·数据库·spring
minji...2 小时前
Linux 多线程(四)线程等待,线程分离,线程管理,C++多线程,pthread库
linux·运维·开发语言·网络·c++·算法
一条闲鱼_mytube3 小时前
TCP流量控制与拥塞控制
服务器·网络·tcp/ip