网络基础——传输层

传输层:负责数据从发送端传输到接收端

端口号

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

在TCP/IP协议中,用“源IP”"源端口号" "目的端口号" "协议号"这样一个五元组来标识一个通信

端口号的划分范围

·0——1023:知名端口号的窗口号都是固定的并众所周知

·1024——65535:操作系统动态分配的端口号

知名端口号

·ssh服务器:使用22端口

·ftp服务器:使用21端口

·telnet服务器:使用23端口

·http服务器:使用80端口

·https服务器:使用443端口

使用 cat /etc/services命令可以查看知名端口号

注意:一个进程可以bind多个端口号(客户端不介意)

         一个端口号不可以被多个进程bind

1、netstat:查看网络状态

·-n:拒绝显示别名,能显示数字的全部转化成数字

·-l:仅列出有在Listen(监听)的服务状态

·-p:显示建立相关连接的程序名

·-t:(tcp)仅显示tcp相关选项

·-u:(udp)仅显示udp相关选项

·-a:(all)显示所有选项,默认不显示LISTEN相关

2、pidof:通过进程名查看进程id

UDP协议

1、UDP协议端口格式

2、UDP的特点

UDP传输过程类似于寄信

·无连接:直到对端的IP和端口号就直接进行传输,不需要建立连接

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

·面向数据报:不能够灵活的控制读写数据的次数和数量

3、面向数据报

应用层交给UDP多长的报文,UDP原样发送,即不会拆分,也不会合并

例:用UDP传输100个字节的数据

如果发送端调用一次sendto,发送100 个字节,那么接收端也必须调用对应的一次revcfrom,接收100个字节;而不能循环调用10次revcfrom,每次接收10个字节

4、UDP缓冲区

·UDP没有真正意义上的发送缓冲区,调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作

·UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,在到达的UDP数据就会被丢弃

UDP的socket即能读也能写,叫全双工

5、UDP使用注意事项

UDP传输的数据(包含UDP首部)最长是64K

6、基于UDP的应用层协议

·NFS:网络文件系统

·TFTP:简单文件传输协议

·DHCP:动态主机配置协议

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

·DNS:域名解析协议

·自己写的UDP应用层协议

TCP协议

TCP:传输控制协议。对数据的传输进行一个详细的控制

1、TCP协议段格式

·源/目的端口号:表示数据是从哪个进程来,到哪个进程去

·32位序号:请求(我的)

·32位确认号:确认(哪些已经收到哪些还得重发、提升效率、保证数据按序到达、保证可靠性、确认那条在那条没有)

·4位TCP报头长度:表示该TCP头部有多少个32位bit,TCP头部最大长度是15*4=60

·6位标志位

    URG:紧急指针是否有效

    ACK:确认号是否有效

    PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走

    RST:对方要求重新建立连接,复位报文段

    SYN:请求建立连接,同步报文段

    FIN:通知对方,本端要关闭了,结束报文段

·16位窗口大小

·16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此校验和包含TCP首部和TCP数据部分

·16位紧急指针:标识哪部分数据是紧急数据

·40字节头部选项

2、连接管理机制

“三次握手,四次挥手”

(1)客户端状态转换

·【CLOSED——SYN_SENT】:客户端调用connect,发送同步报文段

·【SYN_SENT——ESTABLISHED】:connect调用成功,进入ESTABLISHED状态,开始读写数据

·【ESTABLISHED——FIN_WAIT_1】:客户端主动调用close时,向服务器发送结束报文段,同时进入FIN_WAIT_1

·【FIN_WAIT_1——FIN_WAIT_2】:客户端收到服务器对结束报文段的确认,则进入FIN_WAIT_2,开始等待服务器的结束报文段

·【FIN_WAIT_2——TIME_WAIT】:客户端收到服务器发送的结束报文段,进入TIME_WAIT,并发送LAST_ACK

·【TIME_WAIT——CLOSED】:客户端要等待一个2MSL(报文最大生存时间)的时间,才会进入CLOSED状态

(2)服务端状态转换

·【CLOSE——LISTEN】:服务器端调用listen后进入LISTEN状态,等待客户端连接

·【LISTEN——SYN_RCVD】:一旦监听到连接请求,就将该连接放入内核等待队列中,并向客户端发送SYN确认报文

·【SYN_RCVD——ESTABLISHEN】:服务端一旦收到客户端的确认报文,就进入ESTABLISHEN状态,可以进行读写数据

·【ESTABLISHEN——CLOSE_WAIT】:当客户端主动调用close关闭连接,服务器会受到结束报文段,服务器返回我、确认报文段并进入CLOSE_WAIT

·【CLOSE_WAIT——LAST_ACK】:进入CLOSE_WAIT后说明服务器准备关闭连接,当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来

·【LAST_ACK——CLOSED】:服务器收到对FIN的ACK,彻底关闭连接

3、理解TIME_WAIT

·TCP协议规定:主动关闭连接的一方要处于TIME_WAIT状态,等待2MSL的时间后才能回到CLOSED状态

·若server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口

·MSL在RFC1122中规定为两分钟,在Centos7上默认为60s

·通过cat /proc/sys/net/ipv4/tcp_fin_timeout查看MSL的值

为什么TIME_WAIT的时间是2MSL?

·MSL(Max Segment Life):是TCP报文的最大生存时间,因此TIME_WAIT持续存在2MSL的话,就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能是错误的)

·同时在理论上保证最后一个报文可靠的到达

机制

1、确认应答(ACK)机制

TCP将每个字节的数据都进行了编号,即序列号

每个ACK都带有对应的确认序列号。告诉发送者,已经收到了哪些数据,下一次应从哪里开始发

2、超时重传机制

主机A在特定的时间间隔内没有收到主机B发的确认应答,就会进行重发

主机A未收到B发的确认应答,也有可能是ACK丢失了。因此主机B会收到很多重复的数据。TCP协议利用序列号识别并去重

如何确定超时的时间?

·找到一个最小的时间,保证应答一定能在这个时间内返回

·但是这个时间的长短,随着网络环境的不同,是有差异的

·如果超时时间设置的太长,会影响整体的重传效果

·如果超时时间设置的太短,有可能会频繁发送重复的包

TCP为了保证在任何环境下都能比较高性能的通行,会动态计算这个最大超时时间

·Linux中超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍

·如果重发一次之后,仍然得不到,等待4*500ms进行重传。以指数形式递增

·累计到一定的重传次数。TCP认为网络或者对端主机出现异常,强制关闭连接

3、滑动窗口

上述确认应答是:对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段。

为了解决其缺点(是性能较差,特别是在数据往返时间较长时),我们可以一次发送多个数据段(其实就是将多个数据段的等待时间重叠在一起)

·窗口大小指的是无须等待确认应答而可以继续发送数据的最大值

·系统为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据才可以从缓冲区中删除

·窗口越大,则网络的吞吐率就越高

出现丢包时,如何进行重传?

丢包情况一:数据包已经抵达,ACK被丢了

通过后续的ACK进行确认

丢包情况二:数据包直接就丢了

当一段报文丢失后,发送端一直会收到同一个ACK;如果发送端连续3次收到了同样的ACK时,就会将对应的数据包重新发送。接收端收到之后,就会发送另一个ACK了。这种机制叫“告诉重发控制”,又叫“快重传”。

4、流量控制

如果接收端处理数据的速度小于发送端发送的速度会导致接收端的缓冲区被放满,这个时候如果发送端继续发送数据就会引起丢包、重传等一系列反应。因此,TCP会根据接收端处理数据的能力来决定发送端发送的速度。这个机制叫“流量控制”。

·接收端将自己可以接收的缓冲区大小放入TCP首部中的窗口大小,通过ACK端通知发送端

·窗口大小越大,网络的吞吐率越高

·接收端一旦发现缓冲区快满了,就会将窗口大小设置成一个更小的值并通知发送端;发送端接收到窗口大小后就会将自己的发送速度减小

·如果接收端的缓冲区满了,就会将窗口大小设置成0并通知发送端;这是发送端接收不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端

5、拥塞控制

TCP中的滑动窗口虽然能够高效可靠的发送大量的数据,但在刚开始的时候就发送大量的数据依旧可能引发问题,尤其是在网络比较拥堵时。TCP引入慢启动机制(先发少量的数据,摸清当前的网络状况再决定传输数据的速度)

发送开始时定义拥塞窗口为1,每次收到ACK应答时将拥塞窗口加1,每次发送数据包时将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小值作为实际发送的窗口。这样的拥塞窗口增长速度(指数级别)的称为“慢启动”,开始时很慢,但增长速度是很快的。为了使其增长慢下来,我们引入“慢启动的阈值”。当拥塞窗口超过这个阈值时,不再按照指数方式增长,而是按照线性方式增长。在每次重传时,阈值会变成原来的一半,同时拥塞窗口置回1。

6、延迟应答

假设接收缓冲区为1M,一次收到了500K的数据;如果立即应答,返回的窗口大小就是500K;但实际上可能处理的速度很快,10ms之内就把500K数据从缓冲区拿出处理完了。在这种情况下,接收端处理并没有达到自己的极限,即使窗口在大一点也可以处理的过来。如果稍微迟应答一会,返回的窗口就有可能更大一点。

所有的包都可以延迟应答吗?

数量限制:每个N个包就应答一次

时间限制:超过最大延迟时间就应答一次

具体的数量和超时时间因操作系统的不同而不同

7、捎带应答

在很多情况下,客户端和服务端在应用层上都是“一发一收”。客户端给服务器发送了一个消息,服务器也会给客户端发送一个消息,这时ACK可以搭顺风车和服务器发送的消息一起回到客户端

8、面向字节流

创建一个TCP的socket,同时在内核中创建一个发送缓冲区和接收缓冲区

调用write时,数据会先写入发送缓冲区中;如果发送的字节数太长,会被拆分成多个TCP的数据包发送;如果发送的字节数短,就会现在缓冲区等待其长度差不多了或其他适合的时机发送。接收数据时,数据也是从网卡驱动程序到达内核的接收缓冲区;应用程序调用read从接收缓冲区里拿数据。

TCP的一个连接,即有发送缓冲区,又有接收缓冲区;那么这个连接即可以读数据,又可以写数据;这样的叫“全双工”

由于缓冲区的存在,TCP程序的读和写不需要一一匹配

例:写100个字节数据时,可以调用一次write写100个字节;也可以调用100次write,每次写1个字节

       读100个字节数据时,完全不要考虑写的时候是如何写的。即可以调用一次read读100个字节;也可以调用100次read,每次写1个字节

9、粘包问题

包指的是应用层的数据包

在TCP的协议头中,没有和UDP一样的“报头长度”,但是有一个序号

在传输层,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中;在应用层,过来的是一串连续的字节数据

当应用程序看到一连串的字节数据时,并不知道应用层数据包是从哪部分开始哪部分结束

避免粘包问题的方法:明确两个包之间的边界

·对于定长的包,保证每次都按固定大小读取

·对于变长的包,可以在每个包头位置约定一个包的总长度字段

·对于变长的包,还可以在包和包之间使用明确的分隔符

·对于UDP,有很明确的数据边界

10、TCP异常的情况

·进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有区别

·机器重启:和进程终止一样

·机器掉电/网线断开:接收端认为连接还在;一旦接收端有写入操作,接收端就会发现连接已经不在,就会进行reset;即使没有写入操作,TCP也内置了一个保活定时器,会定期询问对方是否还在,如果不在了,就会释放连接

 

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页