TCP/IP协议
TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。
TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓出港口实际表示接收能力,用以限制发送方的发送速度。
如果TCP数据包有已经封好的TCP数据包,那么IP将把他们向“上”传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP将它的信息送到更高层的应用程序,例如Trelnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
面向连接的服务(例如Telnet、Ftp、rlogin、X windows和SMTP)需要高度的可靠性,所以它们使用TCP。DNS在某些情况下使用TCP(发送和接受域名数据库),但是用UDP传送有关单个主机的信息。
1、TCP三次握手
TCP提供面向有连接的通信传输。面向有连接是指在数据同你新年开始之前先做好两端之间的准备工作。
所谓三次握手是指建立一个TCP连接时需要客户端和服务端总共发送三个包以确认连接的建立。在socket编程中,这一过程有客户户端执行connect来触发。
第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器,客户端进入SYN_SENT状态,等待服务器端确认。
第二次握手:服务器端收到数据包后由编制为SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置位1,ack=J+1,随机产生一个值seq=K,并将改数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置位1,ack=K+1,并将改数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务端之间可以开始传输数据了。
2、 TCP的三粗握手的漏洞
但是在TCP三次握手中有一个缺陷,就是如果我们利用三次握手的缺陷进行攻击。这个攻击就是SYN洪泛攻击。三次握手中有一个第二次握手,服务端向客户端应答请求,应答请求时需要客户端IP的,服务端是需要知道客户端IP的,攻击者就伪造这个IP,往服务器端狂发第一次握手的内容,当然第一次握手中的客户端IP地址是伪造的,从而服务端忙于进行第二次握手但是第二次握手当然没有结果,所以导致服务端被拖累,死机。
面对这种攻击,有以下的解决方案,最好的方案是防火墙。
无效连接监视释放
这种方法不停监视所有的连接,包括三次握手的,还有握手一次的,反正是所有的,当达到一定阈值是拆除这些连接,从而释放系统资源。这种方法对于所有的连接一视同仁,不管是正常还是工技大额,所以这种方式不推荐。
延缓TCB分配方法
一般做完第一次握手之后,服务器就需要为改请求分配一个TCB(连接控制资源),通常这个资源需要200多个字节。延迟TCB的分配,当正常连接建立起来后在分配TCB则可以有效地减轻服务器资源的消耗。
使用防火墙
防火墙在确认了连接的有效性后,才向内部的服务器(Listener)发起SYN请求
3、TCP四次挥手(分手)
四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包确认连接的断开。在socket编程中,这一过程客户端或服务端任一方执行close来触发
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIIN来终止之一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上任然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
1、客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部FIN=1,其序号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。TCP规定,FIN报文段即使不携带数据也要消耗一个序号。
2、服务器收到连接释放的报文,发出确认报文,ACK=1,ack=u+1,并且带上字节序列号seq=v,此时,服务器进入CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,及客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的 时间。
3、客户端收到服务器端的确认请求后,此时,客户端进入FIN-WAIT-2(终止等待2)状态,等待服务器发送链接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4、服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能有发送一些数据,假定此时的序列号为sqp=w,此时,服务器就进入LAST-ACK(最后确认)状态,等待客户端的确认。
5、客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的徐磊好是seq=u+1,此时,客户端就进入2*MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的书简要比客户端早一些。
4、TCP的通讯原理
⑴、Socket套接字
Socket的愿意是“插座”,在计算机通信领域,scoket被翻译成“套接字,它是计算机之间进行通信的一种约定或一种方式”。通过socket这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。TCP用主机的IP地址加上主机的端口号作为TCP连接的端点,这种端点就叫做套接字(scoket)。
区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。通过将3个参数结合起来,与一个“插座”socket绑定,应用层就可以和传输层套接字接口区分来自不同应用进程或网络连接的通信,实现数据传输的并发服务。
套接字对是一个定义该连接的两个端点的四元组:本地IP地址、本地TCP端口号、外地IP地址、外地TCP端口号。套接字对唯一便是一个网络上的每个TCP连接。
⑵、TCP缓冲区
每个TCP的socket的内核中都有一个发送缓冲区和一个接受缓冲区。现在我们假设用write()方法发送数据,使用read()方法接受数据。
Write()并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们合适发送到网络,这些都是TCP协议负责的事情。
TCP协议独立于write()函数,数据有可能刚被写入缓冲区就被发送到网络,也可能在缓冲区不断积压,多次写入的数据被一次性发送到网络,这就取决于当时的网络情况、当前线程是否空闲等诸多因素,不有程序员控制。
Read()也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。
总的来说,I/O缓冲区自在每个TCP套接字中单独存在;I/O缓冲区在创建套接字时自动生成。
TCP的可靠性性
在TCP中,当发送端的数据到达接收主机时,接收端主句会返回一个已收到消息的通知。这个消息叫做确认应答(ACK)。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。
在一定时间内没有等待到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丢包,仍然能保证书能够到达对端,实现可靠传输。
为收到确认应答并不意味着数据一定丢失。也有可能是数据对方已经收到,只是返回的确认应答在途中丢失。这种情况也会导致发送端误以为数据没有到达目的地而重发数据。
此外,也有可能因为一些其他原因导致确认应答延迟到达,在源主句重发数据以后才到达的情况也屡见不鲜。此时,源主机只要按照机制重发数据即可。
对于目标主机来说,反复收到相同的数据是不可取的。为了对上层应用提供可靠的传输,目标主机必须放弃重复的数据包。位置我们引进了序列号。、
序列号是按照顺序给发送数据的每一个字节(8位字节)都标上号码的编号。接受端查询接收数据TCP首部中的序列号和数据的长度,将自己下一步应该接收的序列号作为确认应答返回。通过序列号和确认应答号,TCP能都识别是否已经接收数据,又能够判断是否需要接收,从而实现可靠传输。
TCP的滑动窗口
发送方和接收方都会维护一个数据帧的序列,这个序列被称为窗口。发送方的窗口大小由接收方确认,目的是控制发送速度,一面接收方的缓存不够大导致溢出,同时控制流量也可以避免网络拥塞。
在TCP的可靠性的图中,我们可以看到,发送方每发送一个数据接收方就要给发送发一个ACK对这个数据进行确认。只有接受了这个确认数据以后发送发才能传输下个数据。
存在的问题:如果窗口过小,当传输比较大的数据的时候需要不停的对数据进行确认这个时候就会造成很大的延迟。
如果窗口过大。我们假设发送发一次发送100个数据,但是接收方只能处理50个数据,这样每次都只能处理50个数据进行确认。发送方下一次还是要发送100个数据,但是接收方还是只能处理50个数据。这样就避免了不必要的数据来拥塞我们的链路。
因此,我们引入了滑动窗口。滑动窗口通俗来讲就是一种流量控制技术。
它本质上市描述接收方的TCP数据缓冲区大小的数据,发送方根据这个数据来计算自己嘴都能发送多长的数据,如果发送方收到接收方的窗口大小为0的TCP数报,那么发送方就停止发送数据,等到接收方发送窗口大小不为0的数据报的到来。
首先是第一次发送数据,这个时候的窗口大小是根据链路宽带的大小来决定的。我们假设这个时候窗口的大小是3。这个时候接收方收到数据以后会对数据进行确认告诉发送方我下次希望收到的数据是多少。这里我们看到接收方发送的ACK=3(这是发送方发送序列2的回答确认,下一次接收方希望接受到的是3序列信号)。这个时候发送方收到这个数据以后就知道我第一次发送的3个数据对方只收到2个。就知道第3个数据对方没有收到。下次在发送的时候就从第3个数据开始发。
此时窗口大小变成2。
于是发送方发送2个数据。看到接收方发送的ACK 是5就表示它下一次希望收到的数据是5,发送方就知道我刚才发送的2个数据对方收了,这个时候发送第5个数据。
这就是滑动窗口的工作机制,当链路变好了或者变差了这个窗口还会发生变化,并不是第一次协商好以后就永远不变了。
所以滑动窗口协议,是TCP使用的一种流量控制方法。改协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每2发一个分组就停下来等待确认,因此该协议可以加速数据的传输。
只有在接受窗口向前滑动时(与此同时也发送确认),发送窗口才有可能向前滑动。
收发两端的窗口按照以上规律不断向前滑动,因此这种协议又称为滑动窗口协议。