更多优质内容
请关注公众号

计算机网络基础(九)传输层——传输层概述和UDP协议-张柏沛IT博客

正文内容

计算机网络基础(九)传输层——传输层概述和UDP协议

栏目:Linux 系列:计算机网络系列谢希仁 发布时间:2022-02-25 16:47 浏览量:75

· 运输层的基本功能

1. 运用层协议为运行在不同主机上的应用进程之间提供了逻辑通信功能,使得运行在不同主机的进程像直连一样。

2. 复用和分解。

3. 差错检验。



tips1: 运输层把从应用层(具体是运行在应用层的用户进程)接收到的报文划分为一个个小块(数据段),交给网络层传输。

tips2: 我们已知运输层有UDP(用户数据报协议)和TCP(传输控制协议)2种传输协议,应用程序在创建套接字时要指定使用哪种运输层协议。

tips3: 进程到进程的数据交付(多路复用和多路分解)和差错检查是两个最低限度的运输层服务,也是UDP能提供的仅有的两种服务。


· 多路复用和多路分解

运输层从协议栈底层接收到数据后是不会直接交付到进程的,而是交给介于协议栈和进程之间的套接字。

在接收端,将运输层报文段中的数据交付给正确的套接字就是多路分解

在发送端,运输层从不同套接字收集数据块(数据来自用户程序)并交付给网络层就是多路复用。复用强调的是多个用户进程能够复用相同的运输层协议,例如不同进程的UDP套接字的发送缓冲区数据能被收集后统一交给运输层的UDP协议处理和封 装。



· 运输层和网络层的关系

运输层为不同主机的应用程序提供了逻辑通信和数据交付服务,网络层为主机和主机提供了逻辑通信和数据交付服务。

运输层是基于网络层的服务的,只有实现了主机间逻辑通信才能再此基础上实现端到端进程间通信;运输层是网络层的功能扩展,网络层不能保证数据的可靠传输,而运输层则扩展了这个功能。

总结就是:网络层是运输层的基础和服务者,运输层是网络层的扩展,其实协议栈的每个上下层都是这个关系。




· 端口号

运输层用一个16位的端口号标志一个端口,作用是标志本应用层各个进程和运输层交互的层间接口,一个端口也是本机某个进程的标识。


端口号分为3类:

1. 服务端使用端口

A. 熟知端口(0~1023号端口)

作为指定用途的端口(如80是Web服务器端口),不会随机对口进行分配


B. 登记端口(1024~49151)

可作为服务器进程被随机分配的端口


2.客户端使用的端口(49152~65535)

客户端在与对端连接通信时动态选择,连接关闭后端口就关闭,被系统收回,因此又叫短暂端口。


· 无连接下的多路分解

介绍无连接下的多路分解其实就是介绍无连接下运输层如何将数据交付给正确的UDP套接字。

要介绍这一点,我们得看一下UDP的套接字编程:

# 服务端代码
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # 使用IPv4和UDP运输协议
s.bind(("127.0.0.1", 8081))

while True:
    msg, addr = s.recvfrom(2048)        # 无需接收连接,直接接收消息
    print("addr: %s:%s; msg: %s" % (addr[0], addr[1], msg.decode()))
    s.sendto("OK".encode(), addr)

s.close()



# 客户端代码
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # 使用IPv4和UDP运输协议
addr = ("127.0.0.1", 8081)

while True:
    data = input("enter something: ")
    if not data or data == "quit":
        break
    s.sendto(data.encode(), addr)       # 直接消息,无需建立连接,由于没有和服务端交换控制信息,所以每次发送消息都要告诉协议栈目标IP和端口
    msg, _ = s.recvfrom(2048)
    print(msg.decode())

s.close()


1.无论是客户端还是服务端创建一个UDP套接字(socket()),协议栈运输层会为这个套接字分配一个1024~65535的未被占用的端口。0~1024是有特定用途的端口,系统不会随意自动分配(如80、21、25等端口)。应用程序也可以为这个UDP套接字主动指定一个特定端口(bind())。套接字对象也会对应一个能代表套接字标识的文件描述符fd。

2. 内核把(IP,端口)作为成员属性写到这个套接字对象中。并且内核会保存 这个IP和端口与套接字文件描述符fd的映射。

3. 当主机A(可能是发送端or接收端)接收到报文段,该报文段如何交付给主机A正确的套接字进而交付给正确的进程呢?

答案是通过报文段头部的目标IP和端口(实际上只需要目标端口即可),从映射表找到对应的fd,再找到对应的套接字对象。

报文段的数据会拷贝到该套接字的接收缓冲区完成交付。

用户进程从套接字的缓冲区把数据拷贝到用户进程的空间即可。


tips: 另外看到这段代码无需建立连接就可以recvfrom(),说明一端能够接收任意对端的消息。而TCP的一端只能recv到建立了连接的另一端的消息。因此UDP是一个一对多通信,而TCP是一对一通信。


· 面向连接的多路分解

运输层如何将数据交付给正确的TCP套接字。

要介绍这一点,我们得看一下TCP的套接字编程:

# 服务端代码

# 创建套接字
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定ip和端口
ip = "127.0.0.1"
port = 8000
server.bind((ip, port))

# 监听套接字
server.listen()

print("服务已开启")

def contact(client):
    print("客户端 %s 已成功连接" % currentThread().name)

    msg = client.recv(1024).decode("utf-8")  # 接收客户端发送到服务端的消息,这里也会收到阻塞
    while msg:     # 允许接收客户端发送多次消息,如果对方发送空字符,则认为客户端断开连接,此时结束该线程
        print("客户端 %s 发送信息:%s" % (currentThread().name, msg))
        msg = client.recv(1024).decode("utf-8")

    print("客户端 %s 断开连接" % currentThread().name)

while True:
    print("等待接收客户端连接")
    client,addr = server.accept()    # 接受连接, 这里会受到阻塞

    # 创建线程用于客户端和服务端通信
    thread = Thread(target=contact, args=(client,))
    thread.start()



# 客户端代码

# 创建套接字
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定ip和端口
addr = ("127.0.0.1", 8000)


client.connect(addr)

while True:
    msg = input()
    if msg:
        client.send(msg.encode("utf-8"))
    else:   # 如果直接输入换行则断开连接
        client.close()
        break



1. 服务端中有2种TCP套接字,一种是负责接收连接的TCP套接字(代码中的server),它绑定了本机的IP和端口(8000端口),当客户端发送连接请求报文,运输层可以通过报文的目标IP和端口找到该套接字,实现报文段交付。这种只用于接收TCP连接的套接字称为server套接字。

2. 另一种套接字是建立连接后协议栈拷贝server套接字生成的client套接字,专门用于和对应的客户端进行收发数据,client套接字包含了源IP和端口以及目标IP和端口的信息(内核会保存源IP端口和目标IP端口与该套接字fd的映射),接收端接收到报文段后可以根据报文头部的源IP端口和目标IP端口(其实根据源IP端口+目标端口这3个字段就行)定位到正确的client套接字进行数据交付。



总结:UDP协议根据报文段的目标IP和端口定位到对应的socket完成数据向用户进程的交付;而TCP协议则要根据源IP端口+目标IP端口这4个字段定位。

如果2个不同源主机的报文段的目标IP和端口相同:对于UDP,这2个报文段会交付到同一个接收方socket。对于TCP,这2个报文会交付到两个不同的socket。

总结:套接字的逻辑本质是 IP + 端口。连接 = 发送方套接字 + 接收方套接字。

TCP套接字是一个四元组套接字(源IP和端口 + 目的IP和端口),UDP套接字是一个二元组套接字。



· UDP协议

UDP是一种无连接的、面向报文的、尽最大努力交付(不保证可靠交付)的传输层协议。


UDP的特点

不建立连接:减少了3次握手的时延。

不保证可靠交付:报文可能丢失、乱序(但不会比特差错),而且不负责重发。丢失时可以通知应用层,让应用层组织重发。因为不保证可靠交付,所以也没有确认应答机制。

面向报文:一次交付一个完整报文。UDP协议不会对应用层交付给运输层的报文切分(即使这个应用层报文很大),而是直接对应用层报文加上首部就交给网络层(但网络层会对其分片的),保留了报文的边界。需要应用层决定一次发送多少数据以避免发生IP分片。

没有拥塞控制:网络出现拥塞时也不限制发送端的发送速率(对发送端自己有利,但对其所在的网络不利)。这意味着发送速率稳定,但发生拥塞时会因为路由器缓存溢出而丢失分组,而且不限速的发送也会导致拥塞和加重拥塞。

支持多种交互通信:支持一对一,一对多,多对多,多对一的交互通信,而TCP只能做到一对一。这里的一对一和一对多是指socket,具体是指一个服务端的soket可以为多个客户端的socket通信和服务。而TCP服务端的一个client套接字只能为一个客户端socket收发消息。

首部开销小:8个字节,比TCP的20字节首部短。


· UDP使用场景

实时应用:语音电话或视频会议。利用了UDP开销小、效率高、没有拥塞的特点。

一次性传小量数据的应用:如果一次性大量数据则不利于UDP不切分数据的特点。

多媒体应用:如播放视频。因为视频对传输可靠性没那么高,即使小部分数据丢失也不影响视频播放。


· UDP协议报文格式


UDP头部包括源端口、目的端口、长度(包括头部长度+数据长度)和校验和这4个字段,每个字段2个字节。极其简单,不做解释。




· UDP差错检查

UDP的差错检查既检查头部也检查数据部分。差错校验过程如下:


1、在发送端,运输层封装好UDP报文之后,会为其生成一个伪首部,整个报文(包括伪首部、UDP首部和数据部分)被分成多段,每段16个位,如果所有比特数量不是16的倍数则补0。

需要注意,此时UDP首部的校验和为空,用16位的0填充占位。

2、将所有16位的二进制串相加求和得到16位的一个二进制串(如果溢出则把溢出的部分回卷),最后再取反,即为校验和。

如上图所示(图中伪首部的17表示使用UDP协议,15表示UDP报文的长度),报文的第一个16位是伪首部的前2个字节,也是源主机IP的前两个字节153和19,转为二进制是10011001和00010011,同理列出报文剩下的所有16位的二进制串。其中校验和也占2个字节,但是由于校验和目前为空,因此校验和的16个位是 00000000 00000000。最后数据部分不足16位的部分用0填充到满足16位。

上图所有16位比特求和最终为 10 10010110 11101011,一共18位,溢出的两位“10”需要回卷,也就是把“10”加回到最低位得到 10010110 11101101,将其取反就得到校验和 01101001 00010010,它会被填充到报文头部的校验和字段。

之后UDP报文往网络层传递,传递的报文不含伪首部,伪首部只是为了生成校验和的。

3、在接收端,接收到UDP报文后,运输层会把报文加上伪首部之后分为多个16位的段,数据部分不足16位的补0,并将所有16位二进制串相加。由于校验和 和 非校验和的其他字段的16位二进制之和 是互相取反的关系,因此如果求和得到 11111111 11111111 这样的16位1,说明整个UDP报文没有差错。

运输层的差错检验检验了如目标IP和端口、源IP和端口、其他头部字段和数据部分(因为校验和16位二进制是由这些信息构成的)。

TCP的校验和UDP的一样。


运输层差错检验的必要性

虽然链路层也提供了差错检验,运输层依旧有检验的必要,原因有二:

A. 无法保证源和目的之间所有链路都提供差错检验。

B. 即使在链路中没发生比特差错,报文段存储在某个路由器的内存中也可能引入比特差错。


检验差错后

UDP提供差错检验,但不会恢复差错(不会重发出错的分组),接收端如果检测出差错只能丢弃受损报文段,或者是将首个报文段交给接收端应用程序并由应用程序发出警告。

需要注意,网络层也会做校验,但它只对网络包的头部校验而不对数据部分校验,原因是网络层的职责是为了尽可能高效快速的传输数据,如果检验数据部分就会降低这个传输速率。而传输层的职责之一是数据的交付,保证数据的正确性是传输层该做的。这点和协议栈的每一层的功能职责有关。




更多内容请关注微信公众号
zbpblog微信公众号

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > 计算机网络基础(九)传输层——传输层概述和UDP协议

热门推荐
推荐新闻