UDP与TCP协议

很抱歉,我之前写好的UDP与TCP文章不小心被删了,所以,这篇文章只有一半,后面我会尽快补全。

在完成HTTPS的学习后,我们就完成了应用层的所有讲解,下面我们开始讲解传输层,这一层常用的协议为TCP和UDP。

一、再谈端口号

1.端口号

端口号(port)标识了一个主机上进行通信的不同的应用程序。

如图所示,在一个机器上运行着许多进程,每个进程使用的协议都不一样,比如FTP,SSH,SMTP,HTTP,FTP等。

正是因为每一个进程都有自己的端口号(如图中TCP21,TCP22这些,后面的数字就是端口号)当发来的数据从网络中传输到应用层后,操作系统就能根据端口号将数据交给对应的进程。

2.五元组

TCP/IP协议是传输数据常用的协议,它会用 “源IP”、“源端口号”、“目的IP”、“目的端口号”、“协议号” 这样一个五元组来标识一个通信。

如下图所示,客户端A打开了两个浏览器页面(可认为是两个进程)向服务器分别发送数据1和数据2。所以在这两份数据的五元组中,源IP地址都是客户端A的IP地址,目标IP地址都是服务器的IP地址,源端口号分别是2001和2002,它们能标识这两个进程,目标端口号都是服务端的HTTP进程,HTTP使用的端口号是80。

客户端B也打开一个浏览器页面(可认为是一个进程)向服务器发送的数据3。所以在这份数据的五元组中,源IP地址就是客户端B的IP地址,目标IP是服务端的IP地址,源端口号是这个页面进程的端口号,目标端口号是服务器HTTP进程的端口号80。

协议号是通信协议的编号,指定的协议号可以标识一种协议,比如6号就标识TCP协议。

IP地址属于IP协议的内容,IP协议属于网络层,在传输层处不做讨论。

3.端口号划分

在前面编写套接字代码的时候,端口号的类型是uint16_t,本质是一个16位的无符号整数。由于这个整数的最大值是65535,所以端口号的范围是0~65535。

这些端口号可以分为知名端口号和操作系统动态分配的端口号。

(1)知名端口号

0~1023范围内的端口号叫做知名端口号,这些端口号常被固定的服务绑定,如HTTP、FTP、SSH等这些广为使用的应用层协议,他们的端口号都是固定的。由于应用层协议本质上是进程在使用,所以在这里应用层协议、进程可以看作是等价的。

可以这样理解,110对应的是报警电话,120对应的是急救电话,119是火警电话,这些号码已经跟这些公共服务强绑定了。这些放在端口号上也一样,0~1023这些端口号都有对应的协议,不能随便更改,就像报警电话不会随便更改一样。所以,我们自己写程序时,要避开0~1023这些知名端口号。

下面是一些服务的端口号:

服务

端口号

SSH

22

FTP

21

TELNET

23

HTTP

80

HTTPS

443

在Linux机器中,有一个文件/etc/services,它存储了所有具体端口号对应的服务协议。我截取了该文件的一部分,可以清楚地看到http的端口号是80。

(2)操作系统动态分配的端口号

剩下的1024~65535这些端口号就可以由我们指定去绑定某个进程,比如我们之前使用的8080、8081、8082这些。

除了自己用bind函数显式绑定,操作系统还可以自动从这些端口号中选择一个分配给某个进程。比如说,我们之前写的客户端的套接字就并没有使用bind绑定端口号,在调用sendto函数时,操作系统就会自己从1024~65535中随机指定一个端口号绑定。

(3)端口号与进程之间的关系

由于端口号是标识一个进程的标识符,所以根据一个端口号必须找到一个唯一的进程。

换句话说,一个端口号不能被多个进程绑定。

因为一个进程绑定多个端口号并不破坏一个端口号必须找到一个唯一的进程的特性。

所以,一个进程可以绑定多个端口号。

4.一些Linux指令

(1)netstat

netstat指令前面已经用过好多次。

语法:netstat+[选项](例:netstat -lntp)

功能:可用于查看当前机器的网络状态。

常用选项:

  • n 拒绝显示别名,能显示数字的全部转化成数字
  • l 仅列出有在 Listen (监听) 的服務状态
  • p 显示建立相关链接的程序名
  • t (tcp)仅显示tcp相关选项
  • u (udp)仅显示udp相关选项
  • a (all)显示所有选项,默认不显示LISTEN相关

(2)pidof

还有一个指令pidof使用起来也非常的方便。

语法:pidof+[进程名](例:pidof server)

功能:得到进程名对应的pid值。

我们之前查看进程的pid时总需要用使用ps ajx查看所有进程,还要自己找对应的进程。现在直接使用pidof就能返回进程的pid。

还有我们如果想对进程进行处理,往往都需要它的pid,pidof与其他指令异同使用会很方便。我以终止进程为例。

我们的httpserver还在运行,想中止它,我们可以输入pidof httpserver | xargs kill -9,其中xargs表示把管道传送过来的数据追加到后面的语句中。这样整个语句就变为kill -9 pid,从而终止进程。

二、UDP

1.协议格式

下图就是UDP协议的格式,前八个字节属于协议报头,之后的是有效载荷。

UDP协议的前八个字节作为报头,64个比特位。其中这八个字节的前16位0-15存放的是源端口号,第16~31位存放目的端口号,32~47位存放的是UDP的长度,48~64位存放的是UDP校验和。

  • 16位源端口号:表示发送端(客户端)的端口号。
  • 16位目的端口号:表示接收端(服务端)的端口号。
  • 16位UDP长度:整个UDP数据段(报文)的长度,包括报头和有效载荷,UDP数据段最大64KB。
  • 16位校验和:由操作系统进行校验,如果发送方和接收方的校验和不一致,说明出错,就会丢弃整个UDP数据段。

UDP数据段最长不能超过64KB,所以如果传输的数据超过了64KB,就需要用户在应用层手动将数据分成多个大小小于等于64KB的数据包,并进行多次发送,在接收端用户也需要手动将各分包重新拼装。

2.解包和分用

解包的最关键问题在于如何把报头和有效载荷进行分离,而分用最关键的在于计算机收到的信息怎么传递给需要的进程。

(1)解包

UDP协议是传输层协议,由操作系统维护,而Linux操作系统又是由C语言写的,所以UDP的报头一定会在操作系统中有自己的结构化数据,我们如果自己写一个结构体描述差不多就是这样:

struct udp_hdr
{uint16_t src_port;//16位源端口号uint16_t dest_port;//16位目的端口号uint16_t length;//16位UDP长度uint16_t check;//16位UDP校验和
};

当然将各变量改为unsigned int src_port:16;这样的结构也可以。

以C语言的知识理解报头与有效数据的分离,我们可以认为当计算机接收UDP数据时,该数据会先放在操作系统的已创建的内核缓冲区内(最大为64KB)。然后创建一个hdr指针指向UDP报头起始位置,再再偏移报头字节数(sizeof(udp_hdr))构建一个start指针指向内核中有效载荷的起始位置。最后根据报头的结构化数据将数据将各个数据(包括正文内容)拷贝到内存,这样就能实现了分离。

上面过程的伪代码:

char* hdr = malloc(XXX);//操作系统创建内核缓冲区
char* start = hdr + sizeof(struct udr_hdr);//指向有效载荷
strcpy(start,buffer,len);//将用户缓冲区中数据复制到内核缓冲区有效载荷处。
(struct udp_hdr*)hdr->src_port = xxx;//赋值源端口
(struct udp_hdr*)hdr->dest_port = xxx;//赋值源端口
(struct udp_hdr*)hdr->length = xxx;//赋值源端口
(struct udp_hdr*)hdr->check = xxx;//赋值源端口

(2)分用

分用时,操作系统中已经维护了一个哈希表,使用绑定的端口号作为key值,就能直接找到这个进程,将有效载荷交给进程即可。所以,进程只要使用网络就一定要绑定端口号,不管是否使用bind显式绑定,这个绑定的过程本质上就是将数据插入哈希表。

3.特点

UDP协议有以下特点:

(1)无连接:只需要指定目的IP和目的端口就可以直接进行传输,不需要建立连接。

(2)不可靠:没有确认机制,没有重传机制,如果因为网络故障该数据段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。

UDP发送数据的方式就像发邮件,发送者只管发出去,至于对方能不能收到完全不关心。

(3)面向数据报:不能够灵活控制读写数据的次数和数量。

  • 应用层交给UDP多长的报文,UDP原样发送,既不拆分,也不合并。
  • UDP发送数据段时,一次性将内核缓冲区中的数据全部发送出去。
  • 接收端会一次性接收发送端发送的所有数据,不能分多次接收。

比如快递,你发快递只能一个一个发,不能先发半个,然后再发半个。收快递也是,不能先收半个,然后再收半个,只能一个个完整的快递进行收发。

4.TCP缓冲区

我需要先解释TCP的缓冲区,然后UDP的缓冲区我们就更好理解了。

还记得之前用过的send/sendto、recv/recvfrom这样的的接口吗?这些系统调用直接就能把数据发出去了?

结论当然是否定的。系统调用的工作在操作系统和用户应用的界限之间,而在网络的分层模型中,数据会一层一层向下传递并在物理层发出,所以这些系统调用的任务一定是从应用层将数据向操作系统传递。

在TCP协议中,操作系统会为通信双方各自维护一个发送缓冲区,一个接收缓冲区。用户层在调用send/sendto函数之后,操作系统会自动对需要发送的内容拼接TCP报头(TCP报头的具体内容后面会讲)形成数据段,然后拷贝到到发送缓冲区中。

同样,本主机从对端主机收到数据段后,也会先将其放入接收缓冲区中。当用户层读使用recv/recvfrom这样的系统调用时,系统调用就会将接收缓冲区内的数据拷贝到应用层中,具体点说就是拷贝到接收数据的字符串中。

所以,send/sendto、recv/recvfrom本质上是一个拷贝接口,它们前者负责将应用层的数据拷贝到发送缓冲区,后者负责将数据从接收缓冲区拷贝到应用层。

在两个缓冲区中的数据由TCP的内部代码进行发送和接收,用户只负责将数据放入或拿出这两个缓冲区。正是因为数据的传输无需用户参与,所以TCP的全名叫做传输控制协议。

而且这两个缓冲区使得通信双方进程在同一时刻,既可以发送数据,也可以接收数据,且互不影响,我们称之为全双工。

5.UDP缓冲区

UDP协议与TCP相似,只是少了一个发送缓冲区。当客户端使用UDP协议将用户层的数据使用sendto发送的时候,数据会被直接拷贝到内核中,经过一定处理后立即发出。

在使用UDP协议接收数据时,操作系统将发送来的数据存放在接收缓冲区中,在适当的时候,操作系统会将数据交给用户层。

UDP的信息传输方式也实现了发送和接收数据同时进行和互不干扰,也叫做全双工。

6.常见的基于UDP的应用层协议

缩写

全名

NFS

网络文件系统

TFTP

简单文件传输协议

DHCP

动态主机配置协议

BOOT

启动协议(用于无盘设备启动)

DNS

域名解析协议

上面这些协议在传输层都是使用的UDP协议,其中很多我们天天都在用。

比如说DNS域名解析协议,我们之前说url中像baidu.com这样的域名本质上是该网站服务器的IP地址。

当我们在浏览器地址栏中输入某个Web服务器的域名时。用户主机首先用户主机会首先在自己的DNS高速缓存中查找该域名所应的IP地址。

如果没有找到,则会使用UDP协议向网络中的某台DNS服务器发送该域名IP地址的查询请求,DNS服务器中有域名和IP地映射关系的数据库。当DNS服务器收到DNS查询报文后,在其数据库中查询,之后将查询的IP地址发送给用户主机。

此时,用户主机中的浏览器可以通过Web服务器的IP地址对其进行访问了。

三、TCP

TCP全称为 “传输控制协议(Transmission Control Protocol”).,它可以对数据的传输进行细致的控制。

1.协议格式

如图所示,TCP协议格式包括20位固定长度数据、选项和数据,其中前20字节加上选项组成报头。我们在这里不讲解选项的内容,你只需要知道这部分不是定长的就可以了。

  • 16位源端口号:发送方进程的端口号。
  • 16位目的端口号:接收方进程的端口号。
  • 32位序号和32位确认号: 后面讲。
  • 4位首部长度: 表示该TCP报头的长度,是一个无符号整数。TCP报头所占字节数=首部长度 * 4,又因为4比特位的无符号整数最大值为15,所以TCP的最大头部长度是15 * 4 = 60字节。
  • 6位标志位:标识TCP数据段的类型,包括URG、ACK、PSH、RST、SYN和FIN,每个都是一个标志位且各自有各自的功能。
  • 16位窗口大小:表示滑动窗口的大小,后面再讲解。
  • 16位校验和:发送端填充CRC校验。接收端校验不通过, 则认为数据有问题,此处的检验和不仅包含TCP首部,也包含TCP数据部分。
  • 16位紧急指针:标识哪部分数据是紧急数据(带外数据)。

TCP协议同样内置于操作系统中,它的报头也是一个C语言编写的结构化数据,只是结构体中的成员变量大小和类型与UDP不同而已。

struct tcp_hdr
{uint32_t src_port:16;uint32_t dest_port:16;uint32_t seq;uint32_t ack_seq;uint32_t header_length:4;......
};

2.解包和分用

TCP的解包与UDP很相似,TCP的报头已经有20字节被固定占用,报头的剩余部分是长度不固定的选项。

所以我们先建立一个指针p1指向这20各字节,可以通过指针访问这些数据。

在TCP报头中存有首部长度,通过首部长度乘以4就得到了报头的字节数,头部长度*4 - 20 = 选项长度,此时我们就可以根据选项的长度构建另一个指向选项头部的指针p2,即p1后移20字节,可以获取选项的内容。

最后根据报头字节数将p1后移构建指针p3,获取正文的内容。

最后分用和之前一样,根据端口号在哈希表中对应进程即可。

3.缓冲区

TCP缓冲区前面已经说过了,操作系统维护了一个发送缓冲区,一个接收缓冲区,实现了全双工。

什么时候将数据段从发送缓冲区发出去,什么时候将数据从接收缓冲区交给应用层?

一次从缓冲区发送多少个字节的数据,一次接受多少数据?

这些全部由内置在操作系统中的TCP协议自行决定。所以说,TCP作为传输控制协议对数据的收发完全自主。

4.面向字节流

我们常说TCP面向字节流的,这又是什么意思呢?

TCP不像UDP那样,一次必须发送或者接收一个完整的数据段。TCP发送与接收数据以字节为单位,不考虑接收到的数据是不是一个完整的数据段。这些流动的字节像河流一样,所以说TCP是面向字节流的。

5.网络协议和协议栈

如下图所示,应用层协议本质上就是进程,而每个进程都有pid,需要使用网络的进程还有一个或多个端口号port,操作系统会维护一个哈希表。操作系统会根据所有使用网络的进程构造(port:pid)的键值对存放在哈希表中,port是key值,pid是value。

在操作系统完成数据段的解包以后,会根据TCP协议中的目的port在哈希表中查找对应进程的pid,有了pid操作系统就能找到PCB,而PCB的文件描述符表中必定有一个fd指向的文件是一个网络套接字。

而套接字本质上也是个文件,所以也会存在一个struct file结构体来管理它,该结构体中的读写缓冲区其实就是TCP协议的接收和发送缓冲区。

最后,将TCP层解包后的有效载荷放入找到的struct file的接收缓冲区中。此时分用中最重要的将数据交给对应进程的任务就完成了,应用层就可以根据文件描述符fd用read读取有效载荷(报文)了,这就完成了数据的接收。

发送的过程也是一样,不过是走了相反的方向。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/160199.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL的index merge(索引合并)导致数据库死锁分析与解决方案 | 京东云技术团队

背景 在DBS-集群列表-更多-连接查询-死锁中,看到9月22日有数据库死锁日志,后排查发现是因为mysql的优化-index merge(索引合并)导致数据库死锁。 定义 index merge(索引合并):该数据库查询优化的一种技术&#xff0…

JOSEF约瑟 漏电继电器 JD1-200 工作电压:380V 孔径:45mm 50~500mA

JD1系列漏电继电器 系列型号 JD1-100漏电继电器 JD1-200漏电继电器 JD1-250漏电继电器 JD1系列漏电继电器原为分体式固定式安装,为适应现行安装场合需要,上海约瑟继电器厂在产品原JD1一体式漏电继电器基础上进行产品升级,开发出现在较为…

从零开始学习调用百度地图网页API:二、初始化地图,鼠标交互创建信息窗口

目录 代码结构headbodyscript 调试 代码 <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><meta name"viewport" content"initial-scale1.0, user-scalable…

黑马JVM总结(三十四)

&#xff08;1&#xff09;JMM概述 &#xff08;2&#xff09;JMM-原子性-synchronized java内存模型是如何保证原子性的呢&#xff0c;它是通过synchroized关键字&#xff0c;来达到这个目的的 第一个线程来了进入同步代码块之后&#xff0c;把这个对象加上锁了&#xff0c;…

LockSupport-LockSupport是什么及等待唤醒机制对比

4.2 LockSupport是什么 LockSupport是用来创建锁和其他同步类的基本线程阻塞原语&#xff0c;其中park()和unpack()而作用分别是 阻塞线程和解除阻塞线程. 4.3 线程等待唤醒机制 4.3.1 三种让线程等待和唤醒的方法 方式一&#xff1a;使用Object中的wait()方法让线程等待&a…

【广州华锐互动】人体血管器官3D动态展示为医学生提供哪些便利?

人体血管器官3D动态展示是一种采用先进的计算机图形技术和立体成像技术&#xff0c;对人体内部结构和功能进行三维可视化的教学方法。这种教学方式以其独特的优势&#xff0c;正在改变传统的解剖学教学模式&#xff0c;为医学教育带来了革新。 首先&#xff0c;3D动态演示能够提…

ROS系列(二):rosbag 中提取视频数据

一、环境安装 当前环境在上一篇文章的基础上进行配置。 ROS系列&#xff08;一&#xff09;&#xff1a;【环境配置】rosbag 包安装_安装rosbag-CSDN博客 继续安装 sudo apt install ffmpeg python 包如下 pip install sensor_msgs --extra-index-url https://rospypi.gi…

互联网Java工程师面试题·Java 总结篇·第三弹

20、重载&#xff08;Overload&#xff09;和重写&#xff08;Override&#xff09;的区别。重载的方法能否根据返回类型进行区分&#xff1f; 方法的重载和重写都是实现多态的方式&#xff0c;区别在于前者实现的是编译时的多态性&#xff0c;而后者实现的是运行时的多态性。重…

ROS opencv 人脸识别

人脸识别需要在输入的图像中确定人脸&#xff08;如果存在&#xff09;的位置、大小和姿态&#xff0c;往往用于生物特征识别、视频监听、人机交互等应用中。2001年&#xff0c;Viola和Jones提出了基于Haar特征的级联分类器对象检测算法&#xff0c;并在2002年由Lienhart和Mayd…

Linux安装rpm包在线安装mysql5.7

以前安装过mysql 前言&#xff1a;检查以前是否装有mysql rpm -qa|grep -i mysql安装了会显示&#xff1a;   bt-mysql57-5.7.31-1.el7.x86_64 停止mysql服务和删除之前安装的mysql rpm -e bt-mysql57-5.7.31-1.el7.x86_64查找并删除mysql相关目录 find / -name mysql/va…

基础课2——自然语言处理

1.概念 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是计算机科学领域与人工智能领域中的一个重要方向&#xff0c;它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。 自然语言处理的主要研究方向包括&#xff1a; 语言学研究&…

【版本控制】Git(学习笔记)

一、Git工作流程图 clone&#xff08;克隆&#xff09;: 从远程仓库中克隆代码到本地仓库checkout &#xff08;检出&#xff09;&#xff1a;从本地仓库中检出一个仓库分支然后进行修订add&#xff08;添加&#xff09;: 在提交前先将代码提交到暂存区commit&#xff08;提交&…

AI算法检测对无人军用车辆的MitM攻击

南澳大利亚大学和查尔斯特大学的教授开发了一种算法来检测和拦截对无人军事机器人的中间人&#xff08;MitM&#xff09;攻击。 MitM 攻击是一种网络攻击&#xff0c;其中两方&#xff08;在本例中为机器人及其合法控制器&#xff09;之间的数据流量被拦截&#xff0c;以窃听或…

css3自动吸附scroll-snap

我们希望可以一块一块的滚动&#xff0c;比如当前一个块滚出去了一部分并且后一个块滚进来一部分的时候&#xff0c;实现后一个块自动滚入或者前一个块回弹到初始位置这种效果&#xff0c;以前的时候用js需要写比较复杂的判断逻辑&#xff0c;后来有了一个css scroll snap这个方…

C# Winform编程(2)常用控件

C# Winform编程&#xff08;2&#xff09;常用控件 常用控件 常用控件 标签&#xff0c;文本&#xff0c;按钮&#xff0c;列表框&#xff0c;组合框等的使用 Program.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks…

apache shiro安全框架反序列化漏洞

用linux搭建一个环境 配置下源vi /etc/apt/sources.list 源如果是kali官方的有时候会下载不了&#xff0c;改成中科大的源 更新下源apt-get update 安装docker-compose 重启kali 启动docker容器 apt-get install docker apt-get install docker-compose reboot service do…

Prometheus的Pushgateway快速部署及使用

prometheus-pushgateway安装 一. Pushgateway简介 Pushgateway为Prometheus整体监控方案的功能组件之一&#xff0c;并做于一个独立的工具存在。它主要用于Prometheus无法直接拿到监控指标的场景&#xff0c;如监控源位于防火墙之后&#xff0c;Prometheus无法穿透防火墙&…

Xilinx IP 10G Ethernet PCS/PMA IP Core

Vivado 10G Ethernet PCS/PMA介绍 1介绍 完整的10G以太网接口如下图,分为10G PHY和10G MAC两部分。 这篇文章重点讲 10G Ethernet PCS/PMA。 2 IP的基本介绍 10G以太网物理编码子层/物理介质连接(PCS/PMA)核心在Xilinx 10G以太网介质访问控制器(MAC)核心和具有10Gb/s…

Maven打包添加本地工程jar包

前言 先吐槽几句,公司有一小组专门来做各个项目的测试环境以及打包上线的工作&#xff0c;我们称之为XX,这个XX并不是什么业务领导&#xff0c;也只是一个螺丝钉。这群人每天对上跪舔&#xff0c;对其他人爱搭不理&#xff0c;给人一种高高在上的感觉&#xff0c;之前的一个老…

【3】c++11新特性(稳定性和兼容性)—>类成员的快速初始化

在进行类成员变量初始化的时候&#xff0c;C11标准对于C98做了补充&#xff0c;允许在定义类的时候在类的内部直接对非静态变量进行初始化&#xff0c;在初始化的时候可以使用等号&#xff0c;也可以使用花括号{}&#xff0c;等号可以省略不写&#xff1b;静态成员变量需要在类…