Socket API简介二(tcp的状态/TCP的四次挥手/TCP和UDP的基本特性)
一.TCP的四次挥手
全双工:弄两条传输线,一条发送一条接收,发送和接收同时进行,目前的网卡一般都支持全双工
半双工:猜出来了,一条传输线,发送和接收不能同时进行。
单工:通信线路上的数据按单一方向传送
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭,这意思就是发送传输和接收传输线都要关闭
(1) A进程首先调用close,我们称A端执行主动关闭,该端的TCP于是发送一个FIN分节,表示数据发送完毕
(2) 接收到这个FIN的对端B执行被动关闭,这FIN由B端的TCP确认,FIN被当成一个文件结束符放在B端的进程(放在已排队等候B端的进程接收的任何其他数据之后),因为FIN的接收意味着B端的进程在相应连接上没有额外的数据可以接收了。
(3) 一段时间后,接收到这个FIN的B进程将调用close关闭它的套接字,这导致它的TCP也发送一个FIN
(4) 接收这个最终FIN的原发送端TCP确认这个FIN
(2)(3)发送的分节都出自B端的TCP,所以可能被合成一个分节(那就和TCP三次握手太像了),同时,在(2)(3)之间,从B端到A端的流动数据是可能的,这叫个半关闭(双通道只关了一条吧)
需认识到,当一个进程无论以何种方式退出,所有打开的描述符都被关闭,这也导致任何TCP连接上也发出一个FIN
和三次握手一样,FIN M对ACK M+1,不过是把第二次握手的一条命令可能拆成两条发.
二.TCP的连接状态
CLOSED:初始态
LISTEN:只能用于服务器(listen就只有服务器调用吧)表示服务器端的某个SOCKET处于接收即将到来的连接的监听状态了
SYN_RCVD:表示接收到了SYN报文,看清楚了,是SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,(可以看看第四章listen的未完成连接队列都处于这种状态)
SYN_SENT:和SYN_RCVD相对应,当客户端socket执行connect连接时,它首先发送SYN报文,因此随后它会进入SYN_SENT状态,等态服务器端发送第二次握手
ESTABLISHED:表示连接已建立了(可以看看第四章listen的已完成连接队列都处于这种状态)
FIN_WAIT_1:其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态(未收到ACK前的状态)。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:发送FIN报文,收到ACK后.
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文(也就是执行了第四次挥手),就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
2MSL即两倍的MSL,MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次挥手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。
CLOSING:正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接
CLOSE_WAIT:当对方close后发送FIN报文给自己,你系统会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
(这时主动关闭方应处于TIME_WAIT状态)
我在想是不是这样看:假定B客户端发起关闭连接,A服务器是被动关闭,在第一次挥手时:B的TCP发FIN,处于FIN_WAIT_1状态,第二次挥手,A回复ACK,B处于FIN_WAIT_2状态,A处于CLOSE_WAIT状态,第三次挥手,A发送FIN,A处于LAST_ACK状态,第四次挥手,B回复ACK,B处于TIME_WAIT状态,
三.UDP
Udp是一个简单的传输层,应用程序写一个数据报到UDP套接口,由它封装成Ipv4或IPv6数据报,然后发送到目的地
最大问题是不可靠,如果我们要确保一个数据报到达目的地,我们必须在应用程序中建立一大堆特性:来自另一端的确认,超时,重传等,每个UDP数据报都有一定长度,如果数据报最终正确的到达目标地,那么数据报的长度将传递给接收方的应用程序,而TCP是字节流协议,无记录边界
UDP是无连接的,因为UDP客户和服务器不必存在长期的关系,也就是它可以不connect就直接收发数据.
UDP本身不提供确认,序列号,RTT估算,超时及重传等机制,如果一个UDP数据报在网上被复制,两份拷贝都可能送到接收方主机,如果一个UDP客户发送两个数据报到同一个目的地,它们可能被网络重排序,颠倒顺序后到达目的地,UDP应用程序必须处理这些情况.
四.TCP
1.TCP是面向连接的,一个TCP客户建立与一个给定服务器的连接,跨越连接与那个服务器交换数据,然后终止接连
2.TCP提供可靠性,当TCP向另一端发送数据时,它要求对方返回一个确认,如果确认没有收到,TCP会自动重传数据并等待更长时间,在数次重传失败时,TCP才放弃,(这只在TCP内部进行)
3.TCP通过给所发送数据的每个字节关联一个序列号进行排序,比如,假定应用程序写2048字节到一个TCP套接口,导致TCP发送2个分节,第一个分节所含数据的序列号为1-1024,第2个分节序列号为1025-2048,如果这些分节非顺序到达,接收方的TCP将根据它们的序列号重新排序,再把结果数据传给应用进程,如果TCP收到重复的数据,它也可以根据序列号丢掉它们。
4.TCP含有用于动态估算客户到服务器所花时间RTT的算法,因此它知道等待一确认需要多少时间。
5.TCP提供流量控制,TCP总是告诉对方它能够提收多少字节的数据,这称为通告窗口,任何时候,这个窗口指出了接收缓冲区中可用的空间,从而确保发送方发送的数据不会溢出接收缓冲区,当接收发送方的数据时,窗口大小减小,当接收方应用程序从缓冲区读取数据时,窗口大小增大。窗口大小为0,表示接收缓冲区满了,它必须等待应用程序从这个缓冲区读取数据后才能再接收从发送方来的数据.
6.TCP是全双工的.