linux网络-----传输层
前言
一.传输层:
数据要交接应用层先通过传输层(给哪个程序发数据)
传输层作用:负责数据能够从发送端传输接收端。对于应用层来说有许多服务,传输层怎么知道把数据发给那个应用服务?
这时就有了端口号:端口号(Port)标识了一个主机上进行通信的不同的应用程序。在服务器和多个客户端通信时,它怎么识别的哪个客户端哪个通信呢?通过五元组,即使端口号相同也可以通过
ip地址区分。可以简单理解为一个ip地址标识唯一个主机,而端口号标识一个主机上的唯一个进程
不过端口号也是不可以随便绑定的,有些服务端口号就是固定:
0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的
1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.那么问题来了?
那一个进程可以绑定多个端口号吗?这是可以的
一个端口号可以绑定多个进程吗,不可以。这样的话,传输层就识别不了应用层哪个进程了。
(1)网络命令:
查看:netstat -n
简单介绍一下查看网络命令:sudo netstat -ntpl
选项:
------t 查看tcp协议的
-------u查看udp协议的。
-----n表示可以显示数字的显示数字
-----l表示处在监听状态的,不带l表示查看不处于监听状态的
-----a如显示监听和非监听状态的
------p是查看服务名称的(PID/program)
如何方便查看进程id?
pidof+进程名:方便查看进程的id
(3)UDP协议
格式:
一个dup数据报形成,可以简单理解为,我们在应用层发送的数据会被拷贝到内核的缓存区,封装报头,就是一个完整的数据报了。但是对于一个服务器来说或者客户端,会大量收到数据报还没来的及处理堆积在内核的缓冲区,就要对它进行管理(转化为对链表的增删查改)
udp特点:
需要注意的是udp长度是16位,所以发送一个数据包不可以超过64k的大小。除非处理后小于64k
(3)Tcp协议
(1)tcp的确认应答机制:
在经过2次发送和2次应答,双方确认了连接的可靠性,发送一次,应答一次,但是这种发方式是串行,为了保证效率。采用了发送时间重叠(同时发送),这是最常见的发送
但是对于这个也会有问题,由于发送经过网络,会造成接收方的顺序不一致。tcp根据报头32位确认序号,进行排序。保证接收和发送的顺序是一致的。
捎带应答:在客户端向服务器发送消息时,由于tcp是全双工,服务器收到消息进行应答时也会携带自己的消息进行发送,所以32位序号和32位确认序号会被同时使用。
32位序号:为保证数据的有序性,对报头进行排序。
32位确认序号:发送方确认历史数据的到达。
16位窗口大小,告知对方接收缓冲区的大小,进行流量控制。
所以tcp保证可靠性的同时,也提高了效率。
六位标记位:实际是区分报文的类型,发送什么类型的报文,该做什么动作。
URG和16位紧急指针是对应的,如果urg被置1, 紧急指针就会被设置。
RST:链接建立认知不一致,在第三次握手时,可能会失败,因为最后一次握手没有ack.如果最后一次报文丢失,客户端因为链接建立好了,而服务端没收到报文,认为没建立好链接。这时客户端向服务器发送消息,服务器就会向客户端发送RST的报文,让客户端重新链接。
二.超时重传机制
主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B; 如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发
但是, 主机A未收到B发来的确认应答, 也可能是因为ACK丢失了。这时主机A就会重发,不过主机B就会收到两个一样的报文,它就会根据32位序号进行去重。
那么重传的时间是如何控制的:Linux中超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.
(1)连接管理机制
tcp连接要经过3次握手和四次挥手。
3次握手(实际是四次握手,其中一次是捎带应答):以最小的成本验证全双工同时保证客户端链接建立成功然后服务端建立连接。
四次挥手:告诉双方不再发送消息。
可以通过系统调用关闭套接字读或者写。
(2)连接状态
对于连接状态,操作系统会在内存中维护一个网络连接的结构体。如果客户端先断开连接,服务端就会先处于close_waite状态,然后客户端收到应答处于fin_waite2。那如果服务端没有close.双方一直处于这两种状态,就是都没有挥手成功,结构体中的状态不处于close.占用大量资源(内存)
这里注意的是主动断开连接的一方会有time_waite状态。
为什么是TIME_WAIT的时间是2MSL?
MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话 就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到 来自上一个进程的迟到的数据, 但是这种数据很可能是错误的); 同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这 时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK)。
二、滑动窗口
在前面说过tcp采用时间重叠发送大量的报文,而滑动窗口的里的就是这等待发送的报文而不需要ACK的数据段。怎么理解呢,客户端需要发送数据就要把数据拷贝到发送缓冲区。我们可以把缓冲区理解为一个字符数组,而滑动窗口是缓冲区的一段区域。
滑动窗口是如何工作的:
滑动窗口的变大,变小,0.
如果发送方发送大量报文,而接收方的缓存区的数据还没有被上层取走。然后接收方返回ack的确认序号,statr++,而end不动(因为缓存区的数据没有被上层读走)直到end和statr指向同一个位置,滑动窗口就为0了。如果缓存区数据被读走了,有空间。返回的ack报文的窗口大小win+原来的statr,窗口就变大了。所以接收方接收能力可以控制发送方发送的数据量,来实现流量控制。
(1)丢包问题:
当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 "我想要的是 1001" 一样; 如果发送端主机连续三次收到了同样一个 "1001" 这样的应答, 就会将对应的数据 1001 - 2000 重新发送; 这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已 经收到了, 被放到了接收端操作系统内核的接收缓冲区中; 这种机制被称为 "高速重发控制"(也叫 "快重传").
(2) 拥塞控制
场景1:如果网络不好,发送方发送大量的报文,而接收方没有接收到,到了一定时间就会超时重传,而一个服务器连接了很多个客户端,大家都因为网络问题发送超时重传,这是不合理的。
拥塞控制就是针对网络问题,对网络状态进行探测,网络通畅,发送的数据就多,不通畅就少。
开始网络探测时,会发送一个报文。如果收到应答,就会增长发送报文数量。当然也受对方接收能力的限制,一般滑动窗口规定为拥塞窗口和对方接收窗口的最小值。
(3)拥塞窗口增长算法:
(4)延迟应答
在接收方收到报文时,并不会立即ack.为了保证传输的效率,会等待一定的实际,等上层应用把缓存区的数据读走,这样返回的窗口大小尽可能的大。
(5)粘包问题
不同与udp,它的报文长度是固定的,本身就可以解决数据和数据之间的边界,问题。你发送多少他就接收多少。而tcp不同,多次写入的数据可能在内核缓冲区中,可能一次发送,数据是连续的,所以要解决粘包问题。
解决粘包问题的方法:
(1)特殊字符
(2)定长报文
(3)报头+自描述字段(http)
(6)listen的第二个参数
在操作系统中会维护两个队列:
1. 半链接队列(用来保存处于SYN_SENT和SYN_RECV状态的请求)
2. 全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求)。
应用层accept不参与3次握手,建立连接是操作系统帮我们完成的,但是如果我们上层没有调用accep请求,就会维护两个队列,一个是已经建立连接处于established状态的,还有一个是尝试建立连接但是服务器不会跟它进行3次握手。全连接会维持一段时间,而半连接一会就消失了。
listen的第二个参数就是设置全连接队列节点的个数(每个节点就是一个以及建立好连接),如果请求的连接超出这个个数,会被维护到半链接队列中。