TCP 和 UDP 的区别

TCP 和 UDP 的区别

在计算机网络中,TCP 和 UDP 是两种常见的传输层协议。它们的设计目标和适用场景有很大不同。以下是两者的详细对比:


1. 面向连接 vs 无连接
  • TCP 是面向连接的协议。

    • 在数据传输之前,客户端和服务端需要通过三次握手建立连接。
    • 这种"连接"实际上是在双方维护了一些状态信息(例如接收窗口、序列号等),用于保证可靠性和顺序性。
    • 为什么需要建立连接?因为 TCP 需要确保双方的状态同步,以便后续的数据传输能够有序且可靠。
  • UDP 是无连接的协议。

    • 数据直接发送,无需建立连接。
    • UDP 不维护任何状态信息,也不关心数据是否被对方正确接收。

代码示例:

go 复制代码
// TCP 示例:建立连接并发送数据
package main

import (
	"fmt"
	"net"
)

func main() {
	// 创建一个 TCP 服务器
	listener, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer listener.Close()

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				fmt.Println("Error accepting connection:", err)
				continue
			}
			go handleConnection(conn)
		}
	}()

	fmt.Println("TCP Server is running on port 8080...")
	select {}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	buffer := make([]byte, 1024)
	n, err := conn.Read(buffer)
	if err != nil {
		fmt.Println("Error reading:", err)
		return
	}
	fmt.Printf("Received: %s\n", buffer[:n])
}
go 复制代码
// UDP 示例:直接发送数据
package main

import (
	"fmt"
	"net"
)

func main() {
	// 创建一个 UDP 服务器
	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:8080")
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer conn.Close()

	fmt.Println("UDP Server is running on port 8080...")
	buffer := make([]byte, 1024)
	for {
		n, remoteAddr, err := conn.ReadFromUDP(buffer)
		if err != nil {
			fmt.Println("Error reading:", err)
			continue
		}
		fmt.Printf("Received from %v: %s\n", remoteAddr, buffer[:n])
	}
}

2. 可靠性
  • TCP 提供可靠交付:

    • 数据包无差错、不丢失、不重复,并按序到达。
    • 如果某个包丢失,TCP 会自动重传。
    • TCP 使用序列号和确认机制来确保数据完整性。
  • UDP 不提供可靠性:

    • 数据包可能会丢失、重复或乱序。
    • UDP 不会进行重传或其他补救措施。

3. 数据传输模式
  • TCP 是面向字节流的:

    • 数据以连续的字节流形式发送,没有明确的边界。
    • TCP 自己维护缓冲区,并根据网络状况调整发送策略。
  • UDP 是基于数据报的:

    • 每个数据包独立发送,有明确的边界。
    • 应用层需要自行处理数据包的顺序和完整性。

4. 拥塞控制
  • TCP 有拥塞控制机制:

    • 当网络拥塞时,TCP 会主动降低发送速率(例如慢启动、拥塞避免)。
    • 这是为了避免网络过载,但可能导致延迟增加。
  • UDP 没有拥塞控制:

    • 应用层告诉 UDP 发送数据,它就直接发。
    • 即使网络拥塞,UDP 也不会主动退缩。

UDP 的三大使用场景

  1. 资源消耗少,对丢包不敏感的应用

    • 适用于局域网或网络环境较好的场景。
    • 示例:DNS 查询(通常使用 UDP)。
  2. 广播或多播应用

    • UDP 支持一对多通信(广播或多播),而 TCP 只支持一对一通信。
    • 示例:在线视频会议、实时语音通信。
  3. 低延迟、高吞吐量需求的应用

    • 对于要求快速响应、容忍少量丢包的场景,UDP 更适合。
    • 示例:实时游戏、直播流媒体。

总结

特性 TCP UDP
连接方式 面向连接 无连接
可靠性 可靠(重传、排序、去重) 不可靠(可能丢失或乱序)
数据模式 字节流 数据报
拥塞控制
适用场景 文件传输、HTTP 等 实时音视频、DNS 等

代码示例总结

TCP 客户端
go 复制代码
package main

import (
	"fmt"
	"net"
)

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer conn.Close()

	message := "Hello, TCP!"
	_, err = conn.Write([]byte(message))
	if err != nil {
		fmt.Println("Error sending data:", err)
	}
}
UDP 客户端
go 复制代码
package main

import (
	"fmt"
	"net"
)

func main() {
	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:8080")
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer conn.Close()

	message := "Hello, UDP!"
	_, err = conn.Write([]byte(message))
	if err != nil {
		fmt.Println("Error sending data:", err)
	}
}

通过以上代码示例,可以清楚地看到 TCP 和 UDP 的实现差异以及各自的适用场景。

相关推荐
Experience-摆渡4 小时前
自建 IP 轮换方案实战:健康探测 + 熔断剔除 + 粘性会话
网络·网络协议·tcp/ip
for_ever_love__5 小时前
HTTP协议及网络请求与响应
网络·网络协议·http
csdn_aspnet6 小时前
Modbus RTU 与 Modbus TCP:它们有什么区别?
网络·tcp/ip·tcp·modbus·rtu
CDN3608 小时前
APP和小程序在地铁里总断连?360CDN上HTTP/3(QUIC),把弱网失败率死死压在0.7%
网络·网络协议·http
吠品10 小时前
SQL Server 版本查询的几种实用方法
数据库·网络协议·ssl
Shadow(⊙o⊙)10 小时前
CMake实战Http+编译、链接选项的使用
网络·网络协议·http
Fxkj88810 小时前
传统企业布局新媒体:自行摸索与IP陪跑模式深度对比
人工智能·网络协议·tcp/ip·媒体
可乐鸡翅yeah_11 小时前
HTTPS 站点下 M3U8 混合内容问题深度排查,HLS 协议安全策略踩坑实录
数据库·网络协议·https·m3u8·m3u8在线
2401_8734794019 小时前
IP地址查询工具技术选型:从四类方案到生产部署的完整评估框架
tcp/ip·ip
rockingdingo21 小时前
Codex Claude 智能体做3D/潮玩/IP设计——装上Craftsman Agent工匠智能体Skills 游泳男孩IP案例分享
网络协议·tcp/ip·3d