UNIX网络编程(二)
UNIX网络编程(二)
UNIX网络编程(二)
用户数据包协议(UDP)
UDP不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨越网络后保持不变,也不保证每个数据报只到达一次。
传输控制协议(TCP)
TCP提供客户与服务器之间的连接,还提供了可靠性。
- TCP含有用于动态估算客户和服务器之间的往返时间(RTT)算法。
- TCP通过给其中每字节关联一个***对所发送的数据进行排序。(UDP本身不提供确认、***、RTT估算、超时和重传等机制)
- TCP提供流量控制。TCP总是告知对端在任何时刻它一次能够从对端接收多少字节的数据,这称为通告窗口。该窗口时刻动态变化:当接收到来自发送端的数据时,窗口大小就减小,但是当接收端应用从缓冲区中读取数据时,窗口大小就增大。(UDP不提供流量控制)
- TCP连接是全双工的。这意味着在一个给定的连接上应用可以在任何时刻在进出两个方向上既发送数据又接收数据。因此,TCP必须为每个数据流方向跟踪诸如***和通告窗口大小等状态信息。
TCP连接的建立和终止
建立一个TCP连接会发生三次握手:
- 服务器必须准备好接受外来的连接。这通常通过socket、bind、listen这三个函数来完成。我们称之为被动打开。
- 客户通过调用connect发起主动打开。这导致客户TCP发送一个SYN(同步)分组。
- 服务器必须确认(ACK)客户的SYN,同时自己也得发送一个SYN分组。
- 客户必须确认服务器的SYN。
TCP连接终止
正常终止一个TCP连接需要四次挥手:
- 某个应用进程首先调用close,我们称该端执行主动关闭,该端的TCP于是发送一个FIN分组,表示数据发送完毕。
- 接收到这个FIN的对端执行被动关闭。这个FIN由TCP确认。
- 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
- 接收这个最终FIN的原发送端TCP(即执行主动关闭的一端)确认这个FIN。
为什么连接的时候是三次握手,关闭的时候却是四次挥手?
答:因为当服务器收到客户端的SYN连接请求分组后,可以直接发送SYN+ACK分组。但是关闭连接时,当服务器收到FIN分组时,很可能并不会立即关闭SOCKET,只有等到客户端所有的分组都发送完了,客户端才能发送FIN分组,因此不能一起发送。故需要四步挥手。
TCP在交互的过程中会出现一些意想不到的情况,导致TCP无法按照正常的四次挥手来释放连接,如果此时不通过其他的方式来释放TCP连接的话,这个TCP连接将会一直存在,占用系统的部分资源。在这种情况下,我们就需要有一种能够释放TCP连接的机制,这种机制就是TCP的RST分组。
TCP异常终止的常见情形:
- 客户端尝试与服务器未对外提供服务的端口建立TCP连接,服务器将会直接向客户端发送RST分组。
- 客户端和服务器的某一方在交互的过程中发生异常(如程序崩溃等),该方系统将向对端发送TCP RST分组,告之对方释放相关的TCP连接。
- 接收端收到TCP分组,但是发现该TCP的分组,并不在其已建立的TCP连接列表内,则其直接向对端发送RST分组。
- 在交互的双方中的某一方长期未收到来自对方的确认分组,则其在超出一定的重传次数或时间后,会主动向对端发送RST分组释放该TCP连接。
- 有些应用开发者在设计应用系统时,会利用RST分组快速释放已经完成数据交互的TCP连接,以提高业务交互的效率
TCP状态转移图
TIME_WAIT状态
该端点停留在这个状态的持续时间是最长分节生命期(MSL)两倍,有时候称为2MSL。
MSL是任何IP数据报能够在因特网中存活的最长时间。
TIME_WAIT状态有两个存在的理由:
- 可靠的实现TCP全双工连接的终止
- 允许老的重复分节在网络中消逝。
TCP端口号与并发服务器
当服务器接收并接受第一个客户的连接时,它fork一个自身的副本,让子进程来处理该客户的请求。
假设在客户主机上另有一个客户请求连接到用一个服务器。客户主机的TCP为这个新客户的套接字分配一个未使用的临时端口。
TCP无法仅仅通过查看目的端口号来分离外来的分节到不同端点。它必须查看套接字对的所有4个元素才能确定由哪个端点接收某个到达的分节。