绪论
“六年之约—jack”。本章是网络协议栈第二个主要模块 传输层,传输层在网络层中是非常重要的,他主要通过储存双方的端口记录数据的来源以及数据最终的去处,并且能一定的保证数据传输到达,以及快速高效的传递。本章主要讲到端口号以及UDP协议的含义和格式,后续将继续补充TCP协议敬请期待。
话不多说安全带系好,发车啦(建议电脑观看)。
传输层
简单来说:
由于一个主机同时运行多个进程,传输层就主要负责向两个主机中进程之间的通信提供服务。他主要通过储存双方的端口记录数据的来源以及数据最终的去处,并且能一定的保证数据传输到达,以及快速高效的传递。
1. 再谈端口号
理解端口号(Port):他其实就是标识了一个主机上进行通信的应用程序(ip找到主机,端口号找到主机中对应的那个软件需要发送/接收)
在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat查看网络);
服务器和客户端中都有:ip + 端口号 = 套接字,套接字在网络中是唯一的,这样就能让其进行相互唯一的对应通信(服务器套接字 <–> 客户端套接字 + 协议 就能实现通信)
查看网络连接:nestat -nltp,具体可看这篇博客
端口号范围划分:
== 0~1023:知名端口号(预留端口)==
HTTP、FTP、SSH等这些广为使用的应用层协议,他们的端口号都是固定的(一般普通用户绑不了,root才行)
常用知名的端口号:
- ssh服务器, 使用22端口
- ftp服务器, 使用21端口
- telnet服务器, 使用23端口
- http服务器, 使用80端口
- https服务器, 使用443
一般1023往后的端口由自己分配使用,端口号也是一种资源,他也是有限的,由自己分配。
一个端口号只能绑定一个进程,一个进程可以绑定多个端口
查看到知名端口号:cat /etc/services指令
直接拿到进程的pid:pidof + 进程名
UDP协议:
UDP协议格式:
在udp协议中设计中端口号(16位)、UDP长度、UDP检验和组成了报头
-
那么如何将报头和有效载荷(也就是数据!)分离?
因为报头中固定报头的长度,当获取了一个UDP报文,取出固定报头就是有效载荷 -
当得到有效载荷后如何向上交付呢?
通过目的端口号在主机中找到对应的软件就能给到数据。 -
如何知道是否把报文收全了呢?
首先去看报头8字节是否够了,若够8字节就表示报头没有问题。再读取有效载荷通过查看16位UDP长度字描述字段这里所写的长度,就能读取后面对应长度的数据。
理解报头:
如何结构实际就是结构体,下面是udp协议结构:
struct udphdr
{
uint32_t src_port:16;
uint32_t dst_port:16;
uint32_t len:16;
uint32_t checksum:16;
};
OS需要对大量的udp/tcp报文进行管理!
这个管理的结构(理解成一个缓冲区):
struct sk_buff
{
char *data;
char *tail;
struct sk_buff* next;
}
通过成员指针来确定数据的位置(存在缓冲区的位置)
data指向数据的开始,tail指向数据的最后
具体管理方法如下:
协议就是一种约定(双方使用同样的结构体,就都能正常拿出想要的数据!)
UDP的特点:
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息
- 面向数据报: 不能够灵活的控制读写数据的次数和数量(即若是要发送100字节则必须一次性在一个数据报中发送(sendto())过去,不能分多次的发送!)
UDP的缓冲区:
- UDP没有真正意义上的 发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;
- UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 如果缓冲区满了, 再到达的UDP数据就会被丢弃
- 根据2,所以UDP本质就是基于链表的队列
UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部).当超过这个长度后就会被截断(对此只能传输小于64K大小的数据)
UDP的socket既能读, 也能写, 所以这个就是所谓的 全双工 概念
本章完。预知后事如何,暂听下回分解。
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量计算机网络细致内容,早关注不迷路。