传输层
只有主机才有的层次
传输层的功能:
- 传输层提供进程和进程的逻辑通信。
- 复用(应用层所有数据都可以通过传输层传再传输到网络层)和分用(收到数据交付给指定进程);
- 传输层(TCP)对收到的报文进行差错检测(传输层和网络层实现可靠传输)
传输层的寻址与端口
端口(逻辑端口):传输层的SAP(服务访问点)标识主机中的进程,只有本地意义
端口号:16bit,标识65535个端口号。
端口号范围: 0~65535 0~1023不推荐使用,在一台主机上唯一标识一个进程
0~1023被知名协议使用:
- ssh服务器, 使用22端口
- ftp服务器, 使用21端口
- telnet服务器, 使用23端口
- http服务器, 使用80端口
- https服务器, 使用443
功能: 操作系统使用网卡接收数据,放到那个socket缓冲区。
一个端口号只能有一个进程使用,一个进程可以使用多个端口号
五元组:一条网络数据包含的五条信息:源IP+源端口+目的IP+目的端口+协议
主机上网络状态的查看
netstat:查看网络状态
常用选项
- n 拒绝显示别名,能显示数字的全部转化成数字
- l 仅列出有在 Listen (监听) 的服務状态
- p 显示建立相关链接的程序名
- t (tcp)仅显示tcp相关选项
- u (udp)仅显示udp相关选项
- a (all)显示所有选项,默认不显示LISTEN相关
UDP(用户数据报)
UDP协议
**特点:**无连接,不可靠,面向数据报
UDP只在IP数据报上添加了很少的功能,复用分用差错检测
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息;
- 面向数据报: 不能够灵活的控制读写数据的次数和数量数据整条收发,灵活性低,不会产生黏包
UDP协议格式
源端口号:不需要收到回复则不需要
UDP校验和:如果出错则丢弃,分用时找不到端口对应的进程就丢弃报文发送ICMP(端口不可达)差错报告报文
udp协议包含字段
udp检验和原理
伪首部:(伪IP首部)IP数据包数据首部协议字段+源IP地址+目的IP地址,只在计算校验和时出现。
UDP的缓冲区
UDP没有真正意义上的 发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作; UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 如果 缓冲区满了, 再到达的UDP数据就会被丢弃; UDP的socket既能读, 也能写, 这个概念叫做 全双工
TCP协议
TCP特点:
面向连接(虚连接),面向字节流,可靠传输,全双工通信
TCP报文首部格式:
1.源端口和目的端口,各占2个字节。
2.序号位:占4个字节,序号范围为0到2的32次方-1,序号增加到2的32次方-1之后,下一个序号变为0,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。首部中的序号字段值指的是本报文段所发送的数据的第一个字节的序号。可对4GB的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。
3.确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。记住:若确认号是N,则表明:到序号N-1为止的所有数据都已正确收到。
4.数据偏移:占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,这个字段实际上是指出TCP报文段的首部长度。
6.保留:占6位。保留为今后使用,目前置为0
7.选项:长度可变,最长可达40字节,当没有选项时,TCP的首部长度是20字节。
8.最大报文段长度MSS,MSS是指每一个TCP报文段中的数据字段的最大长度。
9.窗口,占2个字节,窗口指的是发送本报文段的一方的接收窗口,不是自己的发送窗口,告诉对方:从本报文段 首部中的确认号算起,接收方目前允许对方发送的数据量。窗口值作为接受方让发送方设置其发送窗口的依据。
10.校验和,占2字节。校验和字段检验的范围包括首部和数据这两部分。
11.紧急指针:占2个字节,紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数。当所有紧急数据处理完毕时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为0时也可发送紧急数据。
控制位:
- 紧急URG(URGent):当URG=1时,表明紧急字段有效,告诉系统此报文中有紧急数据,应尽快传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针字段配合使用。
- 确认ACK(ACKnowlegment)仅当ACK=1时确认号字段才有效,TCP规定,连接建立后所有传送的报文段都必须把ACK置1.
- 推送PUSH(PUSH):当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送操作。
- 复位RST(RESET):当RST=1时,表明TCP连接中出现严重错误,必须释放连接,然后再重新建立运输连接。拒绝非法报文段,拒绝连接。
- 同步SYN,在连接建立时用来同步序号,当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意时,则应在响应的报文段中使SYN=1和ACK=1,因此,SYN置1就表示这是一个连接请求或连接接受报文。
- 终止FIN,用来释放一个连接,当FIN=1时,表示此报文段的发送方的数据已发送完毕,并要求释放运输连接。
连接管理:
TCP连接建立
TCP连接释放:
TIME_WAIT
- TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL(maximum segment lifetime) 的时间后才能回到CLOSED状态. 。
- MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s;
- 可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看msl的值;
TIME_WAIT的必要性:
- 如果没有TIME_WAIT,最后一个ack丢失,被动关闭方重发FIN, 主动关闭方没有等待直接关闭,假如启动服务又使用相同的端口,有可能收到上一个连接重发的FIN,对新连接造成影响。
- 若新的客户端使用相同的端口信息,向服务端发送SYN请求但是服务端没有收到SYN最后一个ACK处于LAST_ACK状态,收到SYN判定状态错误,回复RST报文重置连接,对新连接造成影响所以主动关闭方发送最后一个ack之后需要等待:两个MSL
等待时间是2MSL的原因
- 等待ack丢失导致对端重传的FIN包
- 等待网络中所有双方延迟的报文消失
MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话 就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到 来自上一个进程的迟到的数据, 但是这种数据很可能是错误的); 同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这 时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);
可靠传输:
确认和重传 拥塞控制,流量控制,数据校验,和数据合理的分片,连接管理保证了可靠传输。
有序:协议字段中的确认序号和序号,
确认:
确认应答:每一个ACK都带有对应的确认序列号, 告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开发送
刚才我们讨论了确认应答策略, 对每一个发送的数据段, 都要给一个ACK确认应答. 收到ACK后再发送下一个数据段.
这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候
重传:
超时重传:RTTs(加权平均往返时间)
快速重传:冗余ACK
接收端每条数据都要回复,要按序回复,即使后一条到了但是前一条没有到达也不回复后到的数据的ACK,只有上一条回复之后才回复,所以如果发送端收到了第二条的回复说明第一条数据一定到了,即使第一条的回复丢失了也不会重传,当数据连续发送,数据丢失时,接收端连续发送三次(防止网络时延)重传请求,当发送端接收到了第三次重传请求,则会对这条数据重传
流量控制:
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应. 因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫流量控制; 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端; 窗口大小字段越大, 说明网络的吞吐量越高; 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端; 发送端接受到这个窗口之后, 就会减慢自己的发送速度; 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数 据段, 使接收端把窗口大小告诉发送端。
因为可靠传输,牺牲了部分新能;因此引入了几种机制提高性能
滑动窗口机制:连续发送多条数据等待回复
通信双方通过协议中的窗口字段,来协商能够一次发送的最多数据,然后连续发送多条数据;在socket当中使用两个指针维护窗口后沿(起始位置)和前沿(发送的结束位置)。
发送端:若窗口中后沿数据没有接收到ack确认,后沿就不能向前移动,数据就不能从缓冲区移除,接收到ack确认后窗口,前后沿向后移动。
接收端:当接收数据的时候,如果没有接收到第一条数据,则后沿不能移动,只有接收到数据之后,后沿才会向前移动
拥塞窗口机制:慢启动,快增长。
延迟应答机制:尽可能保持窗口大小,保持网络吞吐率
接收方接收数据后不立刻进行确认回复,而是等待一段时间,因为这段延迟的时间内,有可能用户recv将缓冲区中的数据取走,窗口就尽可能地保证最大窗口,保证传输地吞吐量。尽可能地保证滑动窗口地性能。
捎带应答机制:尽量减少不必要的确认应答包
接收方对每一条数据地确认回复都需要发送一个TCP数据报;但是空报头地传输会降低性能因此会考虑在即将要发送地数据报中包含有确认信息(可以少发一个确认的空报头)
面向字节流
创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;
- 调用write时, 数据会先写入发送缓冲区中;
- 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
- 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出 去;
- 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
- 然后应用程序可以调用read从接收缓冲区拿数据;
- 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可
以写数据. 这个概念叫做 全双工
由于缓冲区的存在, TCP程序的读和写不需要一一匹配, 例如:
- 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;
- 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次
read一个字节, 重复100次;
**TCP的粘包问题:**数据没有边界
TCP异常情况
- 进程终止: 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.
- 机器重启: 和进程终止的情况相同.
- 机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即 使没有写入操作, TCP自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放. 另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ 断线之后, 也会定期尝试重新连接。
为什么握手是三次,挥手是四次?
在握手过程中,为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
当客户端发出的第一个连接请求报文段并没有丢失,而是在网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端。本来这是一个早已失效的报文段。但是服务端收到此失效的连接请求报文段之后,就误认为是客户端再次发出的一个新的连接请求。于是就向客户端发出确认报文段,同意建立连接。假设我们不采用“三次握手”,那么服务端发出确认,新的连接就建立成功了。由于现在client并没有发出建立连接的请求,因此不会理睬服务端的确认,也不会像服务端发送数据。但是服务端却以为新的建立已经完成,一直等待消息发送到来。这样,服务端的数据很多数据被白白浪费了。采用“三次握手”可以有效的避免这种情况。客户端不会向服务端的确认发出确认,服务端由于收不到确认,就认为客户端没有建立连接。
所以,三次握手也可以看作为了防止服务端的一直等待而浪费资源。
挥手过程是一个相互的确认过程,首先我们都已知TCP的连接是全双工的,既可以发送也可以接收。那么当双方都确认自己没有数据可以发送,并且都互相表示双方知道对方没有数据之后,那么连接也就断开了。
假设挥手在第三次结束。客户端发送了一个FIN就打算断开连接。那么客户端又如何知道服务端想要断开连接?有可能客户端刚发送完了数据,但是服务端并没有。服务端打算发完了剩下的数据在跟客户端”拜拜“。
此时就出现了矛盾。所以挥手有第四次来进行双发的确认。确认双方的工作都做完了。
SYN泛洪攻击
SYN泛洪攻击利用TCP三次握手协议的缺陷,向目标主机发送大量的伪造源地址的SYN连接请求,使得被攻击方资源耗尽,从而不能够为正常用户提供服务。
在TCP协议中被称为三次握手(Three-way Handshake)的连接过程中,如果一个用户向服务器发送了SYN报文,服务器又发出 SYN+ACK 应答报文后未收到客户端的 ACK 报文,这种情况下服务器端会再次发送SYN+ACK给客户端,并等待一段时间后丢弃这个未完成的连接,这段时间的长度称为SYN Timeout,一般来说这个时间是分钟的数量级。
SYN 泛洪攻击所做的就是利用这个SYN Timeout和TCP/IP协议族中的另一个漏洞: 报文传输过程中对报文的源 IP 地址完全信任进行攻击。SYN 泛洪攻击通过发送大量的伪造 TCP 链接报文而造成大量的 TCP 半连接,服务器端将为了维护这样一个庞大的半连接列表而消耗非常多的资源。这样服务器端将忙于处理攻击者伪造的TCP连接请求而无法处理正常连接请求,甚至会导致堆栈的溢出崩溃
造成SYN洪泛攻击最主要的原因是TCP/IP协议的脆弱性。TCP/IP是一个开放的协议平台,它将越来越多的网络连接在一起,它基于的对象是可信用户群,所以缺少一些必要的安全机制,带来很大的安全威胁。例如常见的IP欺骗、TCP连接的建立、ICMP数据包的发送都存在巨大的安全隐患,给SYN洪泛攻击带来可乘之机。
防范方法
1、缩短SYN Timeout时间,短时间内收不到客户端的ACK回复报文直接丢弃,防止被攻击
2、设置SYN cookie,给每一个请求连接的IP地址分配一个cookie,如果短时间内连续受到某个IP的重复SYN文,认定是受到了攻击,以后从这个IP地址来的包会被丢弃。
3、设置SYN可疑队列
4、使用防火墙
推荐博客链接:https://blog.youkuaiyun.com/justenjoyitpy/article/details/78151239
若服务端出现了大量的TIME_WAIT连接,为什么?如何解决?
这种情况比较常见,一些爬虫服务器或者WEB服务器(如果网管在安装的时候没有做内核参数优化的话)上经常会遇到这个问题,在四次的挥手过程中我们已经可以了解TIME_WAIT状态的出现情况。
1、防止上一次连接的包迷路后重新出现,影响新连接,所以等待被动方发来的FIN包
2、可靠的关闭TCP连接。在主动方发送的最后一个ACK,有可能丢失,这时被动方会重新发FIN包,如果这时主动方处于CLOSED状态,就会响应RST而不是ACK。所以主动方要处于TIME_WAIT,而不能是CLOSED。
解决的方案就是让服务器能够快速回收和重用那些TIME_WAIT资源