TCP与UDP

TCP(传输控制协议)和UDP(用户数据报协议)是两种核心的传输层协议,在可靠性、连接方式、性能和应用场景上有显著区别。以下是两者的详细对比:


1. 核心特性对比

特性 TCP UDP
连接方式 面向连接(需三次握手建立连接) 无连接(直接发送数据)
可靠性 可靠传输(确认、重传、错误校验) 不可靠传输(可能丢包、重复或乱序)
数据传输顺序 保证数据按发送顺序到达 不保证顺序
流量控制 支持(滑动窗口机制) 不支持
拥塞控制 支持(慢启动、拥塞避免等算法) 不支持
头部大小 20-60字节(包含序列号、确认号等字段) 8字节(仅源端口、目的端口、长度、校验和)
传输效率 较低(需建立连接、保证可靠性) 较高(无连接、无复杂控制)
适用场景 需要可靠传输的场景(如网页、文件传输) 实时性要求高的场景(如视频、语音、游戏)

2. 典型应用场景

TCP 的常见应用

  • Web 服务:HTTP/HTTPS(如网页浏览)。
  • 文件传输:FTP、SFTP(需确保文件完整)。
  • 电子邮件:SMTP、IMAP。
  • 远程登录:SSH、Telnet。

UDP 的常见应用

  • 实时音视频:Zoom、WebRTC(容忍少量丢包,优先低延迟)。
  • 在线游戏:实时多玩家游戏(如《英雄联盟》)。
  • DNS 查询:大多数 DNS 请求使用 UDP(快速响应)。
  • 物联网(IoT):传感器数据上报(高频、低带宽)。

3. 数据包结构对比

TCP 数据包头部

plaintext 复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (可选,最多40字节)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

UDP 数据包头部

plaintext 复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

4. 关键机制详解

(1) TCP 的可靠性保障

  • 确认与重传(ACK & Retransmission):接收方需返回确认(ACK),发送方超时未收到ACK则重传数据。
  • 序列号与顺序控制:每个数据包有唯一序列号,接收方按序重组数据。
  • 流量控制(滑动窗口):动态调整发送速率,避免接收方缓冲区溢出。
  • 拥塞控制:通过慢启动、拥塞避免等算法适应网络状况。

(2) UDP 的轻量化设计

  • 无连接:直接发送数据,无需预先建立连接。
  • 无状态:不维护连接状态,适合短时高频通信。
  • 低开销:头部仅8字节,传输效率高。

5. 如何选择协议?

  • 选 TCP
    • 需要数据完整性和顺序(如文件传输、数据库操作)。
    • 网络环境较差(如高丢包率)。
  • 选 UDP
    • 实时性优先(如视频会议、在线游戏)。
    • 高频低延迟场景(如传感器数据上报)。
    • 需要广播或多播(如直播流)。

总结

  • TCP 是"可靠的信使",确保数据准确无误到达,但速度较慢。
  • UDP 是"快速的飞鸟",追求实时性,但可能丢失部分数据。
    根据业务需求权衡可靠性与效率,选择合适的协议。

以下是 Java 中 TCP 和 UDP 通信 的简单示例代码,涵盖客户端和服务端实现:


一、TCP 通信示例

1. TCP 服务端

java 复制代码
import java.io.*;
import java.net.*;

public class TcpServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("TCP服务端启动,等待连接...");
            
            // 接受客户端连接
            Socket clientSocket = serverSocket.accept();
            System.out.println("客户端已连接:" + clientSocket.getInetAddress());
            
            // 接收客户端消息
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String message = in.readLine();
            System.out.println("收到客户端消息: " + message);
            
            // 发送响应
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
            out.println("服务端已收到消息: " + message);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. TCP 客户端

java 复制代码
import java.io.*;
import java.net.*;

public class TcpClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8888)) {
            // 发送消息
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            out.println("Hello TCP Server!");
            
            // 接收响应
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String response = in.readLine();
            System.out.println("服务端响应: " + response);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、UDP 通信示例

1. UDP 服务端

java 复制代码
import java.net.*;

public class UdpServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(8888)) {
            System.out.println("UDP服务端启动,等待数据...");
            
            // 接收数据包
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            socket.receive(packet);
            
            // 解析数据
            String message = new String(packet.getData(), 0, packet.getLength());
            System.out.println("收到客户端消息: " + message);
            
            // 发送响应
            InetAddress clientAddress = packet.getAddress();
            int clientPort = packet.getPort();
            String response = "服务端已收到消息: " + message;
            byte[] responseData = response.getBytes();
            DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length, clientAddress, clientPort);
            socket.send(responsePacket);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. UDP 客户端

java 复制代码
import java.net.*;

public class UdpClient {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket()) {
            // 发送消息
            InetAddress serverAddress = InetAddress.getByName("localhost");
            String message = "Hello UDP Server!";
            byte[] sendData = message.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, 8888);
            socket.send(sendPacket);
            
            // 接收响应
            byte[] buffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
            socket.receive(receivePacket);
            
            String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("服务端响应: " + response);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、运行说明

  1. TCP 通信

    • 先启动 TcpServer,再启动 TcpClient
    • 客户端发送消息后,服务端会响应确认。
  2. UDP 通信

    • 先启动 UdpServer,再启动 UdpClient
    • UDP 是无连接的,客户端直接发送数据包,服务端接收后返回响应。

四、关键区别

操作 TCP UDP
连接方式 需要建立连接(三次握手) 无连接
可靠性 保证数据完整性和顺序 可能丢包或乱序
适用场景 文件传输、Web 请求 实时音视频、游戏、广播
Java 类 SocketServerSocket DatagramSocketDatagramPacket

通过这两个示例,可以直观感受 TCP 的可靠性与 UDP 的轻量化特性。

相关推荐
PhilipJ03034 分钟前
分页优化之——游标分页
java·数据库优化·分页查询·游标分页
liuyang___5 分钟前
spring boot+mybaits多条件模糊查询和分页查询
java·spring boot·后端
xxxlllli29 分钟前
java小白日记38(集合-List)
java·list
油丶酸萝卜别吃30 分钟前
springBoot中不添加依赖 , 手动生成一个token ,并校验token,在统一拦截器中进行校验 (使用简单 , 但是安全性会低一点)
java·spring boot·后端
Answer_ism1 小时前
【SpringMVC】SpringMVC进阶,类型转换器源码分析,json转换,视图解析器,以及操作各种域的API
xml·java·开发语言·后端·spring·tomcat·json
红豆和绿豆2 小时前
Jakarta EE 和传统的 Java EE 主要区别:
java
心向阳光的天域2 小时前
黑马跟学.苍穹外卖.Day08
java·spring boot
没明白白3 小时前
结构型模式之桥接模式:解耦抽象和实现
java·网络·桥接模式
Liii4033 小时前
Java学习——数据库查询操作
java·数据库·学习