TCP和UDP区别

TCP和UDP区别

TCP协议

TCP(Transmission Control Protocol)是一种面向连接、可靠的、基于字节流的传输层通信协议

TCP报文段结构

UDP协议

UDP(User Datagram Protocol)是一种面向无连接的通信协议,相比于TCP,UDP不提供复杂的控制机制,UDP协议允许应用程序在不建立连接的情况下直接发送封装的IP数据包。开发人员选择使用UDP而不是TCP时,应用程序与IP直接进行通信

UDP头部的格式

TCP和UDP的区别

连接方式

  • TCP 就像打电话: 需要先拨号建立连接("喂,能听到吗?"),通话过程中双方会确认彼此是否听清("你刚才说什么?"),如果没听清就重说一遍,挂断后连接就释放了。
  • UDP 就像寄明信片: 写好地址扔进邮筒就完事了,不需要提前和对方打招呼。邮递员会尽力去送,但不保证一定能送到,也不会有回执告诉你对方收到了没有。而且一张明信片就是一整个消息。

传输方式

  • TCP:面向字节流 TCP 不关心应用层发来的数据是什么格式,只把它当作一串没有边界的二进制流。至于数据怎么分段,是 TCP 协议自己决定的。
  • UDP:面向报文 UDP 会保留应用层传下来的报文边界。发送方发一次,接收方就能原样收到一次,不会拆分也不会合并。

可靠性

  • TCP:可靠传输 它有确认应答、超时重传、数据校验和排序等机制,能确保数据无差错、不丢失、不重复、按顺序到达。
  • UDP:尽力而为,不可靠 它没有这些复杂的机制。如果网络质量差,数据包可能丢失、重复或乱序,这些都需要上层应用自己处理

拥塞控制、流量控制

  • TCP 有流量控制(让发送方别太快,避免接收方处理不过来)和拥塞控制(网络拥堵时自动降低发送速度),像个"绅士",会照顾网络和接收方的感受。
  • UDP 没有这些机制。它想发多快就多快,不管网络是否拥堵,像个"愣头青",但也因此可能加剧网络拥堵。

TCP和UDP的应用场景

对数据完整性要求极高,允许速度稍慢。例如:浏览网页(HTTP)、发送邮件(SMTP)、下载文件(FTP)
对实时性要求极高,允许偶尔丢包。例如:视频会议、网络电话(VoIP)、在线游戏(位置同步)、域名查询(DNS)

TCP

  • FTP 文件传输
  • HTTP / HTTPS

UDP

  • 包总量较少的通信
  • 视频和音频等多媒体通信
  • 广播通信

http和https的区别

安全与加密

  • HTTP(超文本传输协议):

明文传输。数据在网络上传输时,是赤裸裸的文本。 隐患:如果有人在网络节点上抓包(比如在咖啡馆连同一个 WiFi),他可以直接看到你传输的内容,比如你正在浏览的网页内容、或者你提交的表单数据。

  • HTTPS(超文本传输安全协议):

加密传输。HTTPS = HTTP + SSL/TLS(安全套接层/传输层安全协议)。 保护:数据在传输前会被加密成密文。即使黑客抓到了数据包,看到的也是一堆乱码,无法破解其中的内容。

http协议

https协议

工作原理与握手过程

  • HTTP:建立 TCP 连接后(三次握手),就直接开始发送 HTTP 请求报文了。

  • HTTPS:多了几步复杂的步骤:

首先进行 TCP 三次握手。
再进行 SSL/TLS 握手。这个过程包括:浏览器验证服务器证书、协商加密算法、生成临时的会话密钥。
握手完成后,后续的所有 HTTP 数据都会用这个密钥进行对称加密传输

demo

tcp

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

public class TcpEchoServer {
    public static void main(String[] args) {
        int port = 12345; // 服务器端口

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("TCP 服务器启动,监听端口: " + port);

            while (true) {
                // 等待客户端连接(阻塞)
                try (Socket clientSocket = serverSocket.accept()) {
                    System.out.println("客户端连接: " + clientSocket.getInetAddress());

                    // 获取输入流和输出流
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(clientSocket.getInputStream()));
                    PrintWriter out = new PrintWriter(
                            clientSocket.getOutputStream(), true);

                    // 读取客户端发送的一行消息
                    String message = in.readLine();
                    System.out.println("收到消息: " + message);

                    // 原样返回(echo)
                    out.println("Echo: " + message);
                } catch (IOException e) {
                    System.err.println("处理客户端连接时出错: " + e.getMessage());
                }
            }
        } catch (IOException e) {
            System.err.println("无法启动服务器: " + e.getMessage());
        }
    }
}


import java.io.*;
import java.net.*;

public class TcpEchoClient {
    public static void main(String[] args) {
        String serverAddress = "127.0.0.1"; // 本地服务器
        int port = 12345;

        try (Socket socket = new Socket(serverAddress, port);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                     new InputStreamReader(socket.getInputStream()));
             BufferedReader userInput = new BufferedReader(
                     new InputStreamReader(System.in))) {

            System.out.println("已连接到服务器,输入消息(输入 'quit' 退出):");

            String userMsg;
            while ((userMsg = userInput.readLine()) != null) {
                if ("quit".equalsIgnoreCase(userMsg)) {
                    break;
                }

                // 发送给服务器
                out.println(userMsg);

                // 接收服务器响应
                String response = in.readLine();
                System.out.println("服务器响应: " + response);
            }
        } catch (IOException e) {
            System.err.println("客户端异常: " + e.getMessage());
        }
    }
}

udp

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

public class UdpEchoServer {
    public static void main(String[] args) {
        int port = 12346; // UDP 端口(与 TCP 不同,避免冲突)

        try (DatagramSocket socket = new DatagramSocket(port)) {
            System.out.println("UDP 服务器启动,监听端口: " + port);

            byte[] receiveBuffer = new byte[1024];

            while (true) {
                // 准备接收数据报
                DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                socket.receive(receivePacket); // 阻塞等待

                // 提取消息
                String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
                System.out.println("收到消息: " + message + " 来自 " + receivePacket.getAddress());

                // 准备响应数据报
                String response = "Echo: " + message;
                byte[] sendData = response.getBytes();
                InetAddress clientAddress = receivePacket.getAddress();
                int clientPort = receivePacket.getPort();

                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
                        clientAddress, clientPort);
                socket.send(sendPacket);
            }
        } catch (Exception e) {
            System.err.println("服务器异常: " + e.getMessage());
        }
    }
}


import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    public static void main(String[] args) {
        String serverAddress = "127.0.0.1";
        int port = 12346;

        try (DatagramSocket socket = new DatagramSocket();
             Scanner scanner = new Scanner(System.in)) {

            InetAddress serverInetAddress = InetAddress.getByName(serverAddress);
            byte[] receiveBuffer = new byte[1024];

            System.out.println("UDP 客户端启动,输入消息(输入 'quit' 退出):");

            while (true) {
                System.out.print("> ");
                String userMsg = scanner.nextLine();
                if ("quit".equalsIgnoreCase(userMsg)) {
                    break;
                }

                // 发送数据报
                byte[] sendData = userMsg.getBytes();
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
                        serverInetAddress, port);
                socket.send(sendPacket);

                // 接收响应
                DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                socket.receive(receivePacket);
                String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
                System.out.println("服务器响应: " + response);
            }
        } catch (Exception e) {
            System.err.println("客户端异常: " + e.getMessage());
        }
    }
}

http&https

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 HttpVsHttpsClient {

    public static void main(String[] args) {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .followRedirects(HttpClient.Redirect.NORMAL)
                .build();

        // 访问 HTTP 网站
        fetchUrl(client, "http://example.com");

        // 访问 HTTPS 网站
        fetchUrl(client, "https://example.com");
    }

    private static void fetchUrl(HttpClient client, String url) {
        System.out.println("\n========== 请求 " + url + " ==========");

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofSeconds(5))
                .GET()
                .build();

        try {
            HttpResponse<String> response = client.send(request,
                    HttpResponse.BodyHandlers.ofString());

            System.out.println("状态码: " + response.statusCode());
            System.out.println("协议版本: " + response.version());
            System.out.println("响应头: " + response.headers().firstValue("content-type").orElse("未知"));
            System.out.println("响应体预览 (前200字符):");

            String body = response.body();
            if (body.length() > 200) {
                System.out.println(body.substring(0, 200) + "...");
            } else {
                System.out.println(body);
            }
        } catch (Exception e) {
            System.err.println("请求失败: " + e.getMessage());
        }
    }
}


import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class SimpleHttpServer {

    public static void main(String[] args) throws IOException {
        // 创建 HTTP 服务器,监听 8080 端口
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);

        // 设置路由
        server.createContext("/", new RootHandler());
        server.createContext("/test", new TestHandler());

        // 使用默认线程池
        server.setExecutor(null);

        // 启动服务器
        server.start();
        System.out.println("HTTP 服务器已启动,访问 http://localhost:8080/");
    }

    static class RootHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String response = """
                    <html>
                        <body>
                            <h1>Hello, HTTP!</h1>
                            <p>这是一个简易 HTTP 服务器。</p>
                            <p>尝试访问 <a href="/test">/test</a> 获取 JSON 响应。</p>
                        </body>
                    </html>
                    """;
            exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
            exchange.sendResponseHeaders(200, response.getBytes().length);
            try (OutputStream os = exchange.getResponseBody()) {
                os.write(response.getBytes());
            }
        }
    }

    static class TestHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String response = "{\"message\": \"Hello, this is JSON\", \"status\": 200}";
            exchange.getResponseHeaders().set("Content-Type", "application/json");
            exchange.sendResponseHeaders(200, response.getBytes().length);
            try (OutputStream os = exchange.getResponseBody()) {
                os.write(response.getBytes());
            }
        }
    }
}
相关推荐
千寻girling2 小时前
一份不可多得的 《 Django 》 零基础入门教程
后端·python·面试
千寻girling2 小时前
Python 是用来做 AI 人工智能 的 , 不适合开发 Web 网站 | 《Web框架》
人工智能·后端·算法
贾铭2 小时前
如何实现一个网页版的剪映(三)使用fabric.js绘制时间轴
前端·后端
xiaoye20182 小时前
Spring 自定义 Redis 超时:TTL、TTI 与 Pipeline 实战
后端
程序员爱钓鱼5 小时前
GoHTML解析利器:github.com/PuerkitoBio/goquery实战指南
后端·google·go
golang学习记5 小时前
从“大泥球“到模块化单体:Spring Modulith + IntelliJ IDEA 拯救你的代码
后端·intellij idea
颜酱6 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
离开地球表面_996 小时前
金三银四程序员跳槽指南:从简历到面试再到 Offer 的全流程准备
前端·后端·面试
UrbanJazzerati6 小时前
Scrapling入门指南:零基础也能学会的网页抓取神器
后端·面试