一、TCP与UDP的异同
Transmission Control Protocol ------ 传输控制协议
UDP:User Datagram Protocol ------ 用户数据报协议
1、相同点
同属 TCP/IP 协议栈的传输层,为应用层提供 端到端 的数据传输服务。
都基于 IP 协议 进行数据路由与寻址。
都使用 端口号 区分不同的应用程序(进程)。
2、区别
| 特性 | TCP | UDP |
|---|---|---|
| 连接性 | 面向连接 :传输前必须通过三次握手 建立连接,结束后四次挥手释放 | 无连接:无需握手,直接发送数据包 |
| 可靠性 | 可靠 :保证数据不丢失、不重复、按序到达 | 不可靠:不保证送达、不保证顺序、丢包不重传 |
| 控制机制 | 有确认应答、超时重传、流量控制、拥塞控制 | 无任何控制机制,仅做简单校验 |
| 数据模式 | 面向字节流(无边界,连续传输) | 面向数据报(有边界,独立发包) |
| 首部开销 | 20~60 字节(变长,含序号、确认号等) | 固定 8 字节(极短,仅含端口、长度、校验和) |
| 传输效率 | 慢(机制复杂、延迟高) | 极快(开销小、无等待、实时性高) |
| 通信模式 | 仅支持单播(一对一) | 支持单播、广播、组播(一对多) |
| 典型应用 | HTTP/HTTPS、FTP、SMTP、文件传输、远程登录 | 视频直播、语音通话、游戏、DNS、实时监控 |
TCP:可靠、慢、像打电话(先连接、再通话、确保听清)。
UDP:不可靠、快、像寄信(直接发、不管是否收到、不管顺序)。
二、Socket套接字
1、概念
局域网和广域网
局域网:局域网将一定区域内的各种计算机、外部设备和数据库连接起来形成计算机通信的私有网络。
广域网:又称广域网、外网、公网。是连接不同地区局域网或城域网计算机通信的远程公共网络。
IP(Internet Protocol):本质是一个整形数,用于表示计算机在网络中的地址。IP协议版本有两个:IPv4和IPv6
IPv4(Internet Protocol version4):
使用一个32位的整形数描述一个IP地址,4个字节,int型
也可以使用一个点分十进制字符串描述这个IP地址: 192.168.247.135
分成了4份,每份1字节,8bit(char),最大值为 255
0.0.0.0 是最小的IP地址
255.255.255.255是最大的IP地址
按照IPv4协议计算,可以使用的IP地址共有 232 个
IPv6(Internet Protocol version6):
使用一个128位的整形数描述一个IP地址,16个字节
也可以使用一个字符串描述这个IP地址:2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b
分成了8份,每份2字节,每一部分以16进制的方式表示
按照IPv6协议计算,可以使用的IP地址共有 2128 个
bash
# linux
$ ifconfig
# windows
$ ipconfig
# 测试网络是否畅通
# 主机a: 192.168.1.11
# 当前主机: 192.168.1.12
$ ping 192.168.1.11 # 测试是否可用连接局域网
$ ping www.baidu.com # 测试是否可用连接外网
# 特殊的IP地址: 127.0.0.1 ==> 和本地的IP地址是等价的
# 假设当前电脑没有联网, 就没有IP地址, 又要做网络测试, 可用使用 127.0.0.1 进行本地测试
作者: 苏丙榅
端口
端口的作用是定位到主机上的某一个进程,通过这个端口进程就可以接受到对应的网络数据了。
bash
比如: 在电脑上运行了微信和QQ, 小明通过客户端给我的的微信发消息, 电脑上的微信就收到了消息
, 为什么?
运行在电脑上的微信和QQ都绑定了不同的端口
通过IP地址可以定位到某一台主机,通过端口就可以定位到主机上的某一个进程
通过指定的IP和端口,发送数据的时候对端就能接受到数据了
端口也是一个整形数 unsigned short ,一个16位整形数,有效端口的取值范围是:0 ~ 65535(0 ~ 216-1)
提问:计算机中所有的进程都需要关联一个端口吗,一个端口可以被重复使用吗?
不需要,如果这个进程不需要网络通信,那么这个进程就不需要绑定端口的
一个端口只能给某一个进程使用,多个进程不能同时使用同一个端口
OSI/ISO 网络分层模型
OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO(国际标准化组织组织)在1985年研究的网络互联模型

物理层 :负责最后将信息编码成电流脉冲或其它信号用于网上传输
数据链路层 :
数据链路层通过物理网络链路供数据传输。
规定了0和1的分包形式,确定了网络数据包的形式;
网络层
网络层负责在源和终点之间建立连接;
此处需要确定计算机的位置,通过IPv4,IPv6格式的IP地址来找到对应的主机
传输层
传输层向高层提供可靠的端到端的网络数据流服务。
每一个应用程序都会在网卡注册一个端口号,该层就是端口与端口的通信
会话层
会话层建立、管理和终止表示层与实体之间的通信会话;
建立一个连接(自动的手机信息、自动的网络寻址);
表示层 :
对应用层数据编码和转化, 确保以一个系统应用层发送的信息 可以被另一个系统应用层识别;
2、三次握手、四次挥手
1)、三次握手(建立连接)
目的:同步序列号,确认双方收发能力正常,建立可靠连接。
客户端(Client) 服务器(Server)
CLOSED LISTEN
| |
1. SYN-SENT → SYN=1, seq=x |
| ------------------------------------------------------------------------------> |
| SYN-RCVD
| |
2. ESTABLISHED ← SYN=1, ACK=1, seq=y, ack=x+1 |
| <------------------------------------------------------------------------------ |
| SYN-RCVD
| |
3. ESTABLISHED → ACK=1, seq=x+1, ack=y+1 |
| ------------------------------------------------------------------------------> |
| ESTABLISHED
步骤:
-
客户端 → 服务器:SYN=1, seq=x(客户端进入 SYN-SENT)
-
服务器 → 客户端:SYN=1, ACK=1, seq=y, ack=x+1(服务器进入 SYN-RCVD)
-
客户端 → 服务器:ACK=1, seq=x+1, ack=y+1(双方进入 ESTABLISHED)
**为什么是三次?**
两次握手无法防止"已失效的连接请求"突然传送到服务器导致错误连接,且无法保证双方收发能力都正常。
2)、四次挥手(关闭连接)
目的:双方安全关闭连接,确保数据传完。
客户端(主动关闭) 服务器(被动关闭)
ESTABLISHED ESTABLISHED
| |
1. FIN-WAIT-1 → FIN=1, seq=u |
| ------------------------------------------------------------------------------> |
| CLOSE-WAIT
| |
2. FIN-WAIT-2 ← ACK=1, seq=v, ack=u+1 |
| <------------------------------------------------------------------------------ |
| CLOSE-WAIT
| |
3. TIME-WAIT ← FIN=1, ACK=1, seq=w, ack=u+1 |
| <------------------------------------------------------------------------------ |
| LAST-ACK
| |
4. TIME-WAIT → ACK=1, seq=u+1, ack=w+1 |
| ------------------------------------------------------------------------------> |
| (等待2MSL后CLOSED) CLOSED
步骤:
-
主动方 → 被动方:FIN=1, seq=u(主动方进入 FIN-WAIT-1)
-
被动方 → 主动方:ACK=1, ack=u+1(被动方进入 CLOSE-WAIT,主动方进入 FIN-WAIT-2)
-
被动方 → 主动方:FIN=1, seq=w(被动方进入 LAST-ACK,主动方进入 TIME-WAIT)
-
主动方 → 被动方:ACK=1, ack=w+1(被动方进入 CLOSED,主动方等待 2MSL 后关闭)
**为什么是四次?**
TCP 连接是全双工,每一方向需独立关闭。被动方收到 FIN 后,可能还有数据要发送,故先回 ACK,等数据发完再发自己的 FIN。
3)、关键状态与问题
-
TIME_WAIT 状态
-
主动关闭方最后等待 2MSL(Maximum Segment Lifetime,通常 2×60s)再彻底关闭。
-
作用:确保对方收到 ACK(若丢失可重传),并让旧连接报文在网络中消逝,避免新旧连接混淆。
-
-
CLOSE_WAIT 状态
- 被动方收到 FIN 后进入,若程序未调用 close() 会长期停留,导致连接泄漏。
-
半关闭状态
- 一方发送 FIN 后仍可接收数据,直到对方也发 FIN。
一句话总结:
三次握手是"你好了吗?我好了,你呢?我也好了。"
四次挥手是"我说完了,好,我也说完了,好,再见。"
4)、流量控制
流量控制可以让发送端根据接收端的实际接受能力控制发送的数据量。它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不会超过该大小的数据,该限制大小即为窗口大小,即窗口大小由接收端主机决定。
TCP 首部中,专门有一个字段来通知窗口大小,接收主机将自己可以接收的缓冲区大小放在该字段中通知发送端。当接收端的缓冲区面临数据溢出时,窗口大小的值也是随之改变,设置为一个更小的值通知发送端,从而控制数据的发送量,这样达到流量的控制。这个控制流程的窗口也可以称作滑动窗口。
3.TCP 服务器编程的详细流程
创建套接字(socket()):调用 socket() 函数创建一个套接字,指定协议族(如 AF_INET 表示 IPv4)、套接字类型(如 SOCK_STREAM 表示 TCP 套接字)和协议(通常为 0)。
绑定地址和端口(bind()):调用 bind() 函数将套接字与指定的地址和端口绑定。需要创建一个 sockaddr 结构体或其派生结构体(如 sockaddr_in),并填充相应的地址和端口信息。
监听连接(listen()):调用 listen() 函数将套接字设置为监听状态,等待客户端的连接请求。listen() 函数的第二个参数 backlog 表示半连接队列的长度。
接受连接(accept()):调用 accept() 函数接受客户端的连接请求。accept() 函数会阻塞,直到有新的连接请求到达。当有连接请求时,accept() 函数返回一个新的套接字,用于与客户端进行通信。
数据传输(send() 和 recv()):使用新的套接字调用 send() 函数向客户端发送数据,调用 recv() 函数从客户端接收数据。
关闭连接(close()):当数据传输完成后,调用 close() 函数关闭与客户端的连接套接字和监听套接字。
三、UDP
dp是一个面向无连接的,不安全的,报式传输层协议,udp的通信过程默认也是阻塞的。
UDP通信不需要建立连接 ,因此不需要进行connect()操作
UDP通信过程中,每次都需要指定数据接收端的IP和端口,和发快递差不多
UDP不对收到的数据进行排序,在UDP报文的首部中并没有关于数据顺序的信息
UDP对接收到的数据报不回复确认信息,发送端不知道数据是否被正确接收,也不会重发数据。
如果发生了数据丢失,不存在丢一半的情况,如果丢当前这个数据包就全部丢失了
1.基本通信流程
服务器:创建socket → 绑定端口(bind()) → 循环调用recvfrom()接收数据 → 处理请求 → 调用sendto()回复。
客户端:创建socket → 直接调用sendto()发送数据 → 可选调用recvfrom()等待回复。
2.通信函数
1.基于UDP进行套接字通信,创建套接字的函数还是socket()但是第二个参数的值需要指定为SOCK_DGRAM,通过该参数指定要创建一个基于报式传输协议的套接字,最后一个参数指定为0表示使用报式协议中的UDP协议。
bash
int socket(int domain, int type, int protocol);
参数:
domain:地址族协议,AF_INET -> IPv4,AF_INET6-> IPv6
type:使用的传输协议类型,报式传输协议需要指定为 SOCK_DGRAM
protocol:指定为0,表示使用的默认报式传输协议为 UDP
返回值:函数调用成功返回一个可用的文件描述符(大于0),调用失败返回-1
2.另外进行UDP通信,通信过程虽然默认还是阻塞的,但是通信函数和TCP不同,操作函数原型如下:
bash
// 接收数据, 如果没有数据,该函数阻塞
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
作者: 苏丙榅
参数:
sockfd: 基于udp的通信的文件描述符
buf: 指针指向的地址用来存储接收的数据
len: buf指针指向的内存的容量, 最多能存储多少字节
flags: 设置套接字属性,一般使用默认属性,指定为0即可
src_addr: 发送数据的一端的地址信息,IP和端口都存储在这里边, 是大端存储的
如果这个参数中的信息对当前业务处理没有用处, 可以指定为NULL, 不保存这些信息
addrlen: 类似于accept() 函数的最后一个参数, 是一个传入传出参数
传入的是src_addr参数指向的内存的大小, 传出的也是这块内存的大小
如果src_addr参数指定为NULL, 这个参数也指定为NULL即可
返回值:成功返回接收的字节数,失败返回-1
bash
// 发送数据函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
作者: 苏丙榅
3.参数:
sockfd: 基于udp的通信的文件描述符
buf: 这个指针指向的内存中存储了要发送的数据
len: 要发送的数据的实际长度
flags: 设置套接字属性,一般使用默认属性,指定为0即可
dest_addr: 接收数据的一端对应的地址信息, 大端的IP和端口
addrlen: 参数 dest_addr 指向的内存大小
返回值:函数调用成功返回实际发送的字节数,调用失败返回-1
3.单播组播和广播
1.核心定义
单播:一对一,一个发送方 → 唯一一个接收方。
广播:一对所有,一个发送方 → 本网段全部主机。
组播:一对一组,一个发送方 → 加入同一组播组的部分主机。
2.相同点
都是网络中数据传输方式。
都基于 IP 网络、可依托以太网链路传输。
发送方都只需发一份数据(广播 / 组播不用给每个人单独发)。
3.区别
| 维度 | 单播 | 广播 | 组播 |
|---|---|---|---|
| 通信方式 | 一对一 | 一对全部 | 一对指定群组 |
| 接收对象 | 唯一目标主机 | 本网段所有主机 | 仅加入组播组的主机 |
| 网络开销 | 目标多时重复发包,占用带宽大 | 全网泛洪,易产生广播风暴 | 网络仅传一份,按需接收,带宽最优 |
| 跨网段 | 可路由,支持跨网段 | 不能跨路由器,路由器默认隔离广播 | 需组播路由协议,可跨网段 |
| 典型应用 | HTTP、TCP 聊天、浏览网页 | ARP 寻址、DHCP 自动获取 IP | 视频直播、IPTV、会议直播、实时流媒体 |
| 资源占用 | 只占用收发双方资源 | 所有主机都要处理报文,浪费资源 | 只有组成员处理,节省资源 |