Internet的传输层有两个主要的协议,无连接的和面向连接的各一个,两个协议互为补充。无连接的协议是UDP,它除了给应用程序提供发送数据包功能并允许他们在所需的层次之上架构自己的协议外,几乎没有做什么特别的事情。面向连接的协议是TCP,该协议几乎做了所有的事情。它建立连接,并通过重传机制增加了可靠性,同时还进行流量控制和拥塞控制。
UDP
User Datagram Protocol,为应用程序提供了一种无需建立链接就可以发送数据包的方法。UDP传输的段(segment)由8bytes的头和有效载荷构成。
当一个UDP数据包到来时,它的有效载荷被递交给与目标端口相关联的那个进程。可以把端口看作应用程序租来接收数据包的邮箱。当接收端必须将一个应答返回给源端时,源端口字段是必须的。UDP长度字段包含8bytes的头和数据两部分的总长度。
UDP协议特别有用的一个领域是client-server应用开发。以这种方式使用UDP的一个应用是域名系统(DNS,Domain Name System)。
UDP是一个实现RPC的良好基础。
UDP被广泛应用于实时多媒体应用。RTP(Real-time Transport Protocol)就是一个在应用层实现的传输协议。
TCP
Transmission Control Protocol 是为了在不可靠的互联网络上提供可靠的端到端的字节流而专门设计的一个传输协议。互联网络与单个网络有很大的不同,因为互连网络的不同部分可能有截然不同的拓扑结构、带宽、延迟、数据包大小和其他参数。TCP的设计目标是能够动态地适应互连网络的这些特性,而且具备面对各种故障时的健壮性。
每台支持TCP的机器都有一个TCP传输实体,传输实体接收本地进程的用户数据流,将他们分割成不超过64KB的分段(通常不超过1460bytes)。每个分段以IP数据报形式发送。
IP层并不保证数据报一定被正确递交到地方,也不指示数据报的发送速度有多快。正是TCP负责既要足够快地发送数据报,以便使用网络容量,但又不可以引起网络拥塞;而且TCP超时后,要重传没有递交的数据报。即使被递交的数据报,也可能存在错序的问题,这也是TCP的责任,它必须把接收到的数据报重新装配成正确的顺序。
TCP服务模型
TCP服务由发送端和接收端创建一种称为套接字(socket)的端点来获得。为了获得TCP服务,必须显式地在一台机器的套接字和另一台机器的套接字之间建立一个连接,每个连接可以用(socket1,socket2)来表示。
1024以下的端口号被保留,只能用作特权用户启动的标准服务,这些端口称为知名端口。例如:FTP(20,21)、SSH(22)、SMTP(25)、HTTP(80)、HTTPS(443)等等。
所有的TCP连接都是全双工,点到点的。
一个TCP连接就是一个字节流,而不是消息流。端到端之间不保留消息的边界。
当一个应用将数据传递给TCP时,TCP可能立即将数据发送出去,也可能将它缓冲起来,这完全由TCP软件自己来决定。然而,有时候应用程序确实希望数据立即被发送出去。为了强制将数据发送出去,TCP有个PUSH标志位,用于告诉TCP不要延迟传输。
TCP协议
TCP实体使用的基本协议是具有动态窗口大小的滑动窗口协议。当发送端传送一段时,它启动一个计时器。当该段到达接收方时,接收端的TCP实体返回一个携带了确认号和剩余窗口大小的段,并且确认号的值等于接收端期望接收的下一个序号。如果发送端的计时器在确认段到达之前超时,则发送端再次发送原来的段。
每个段的起始位置都是一个20bytes的固定头。其后跟着可选头和用户数据。
上图中的保留位(未使用)现在只剩4bits,有2bits也用作了flag位,也就是有8个flag位。
- 源端口/目标端口:2bytes * 2
- 序号(sequence number)和确认号(Acknowledgement number):4bytes * 2。序号为为当前端成功发送的数据位数。确认号为当前端成功接收的数据位数+1。
- TCP头长度字段指明了TCP头包含了多少个32bits的字。
- 8个flags位
- CWR和ECE用作拥塞控制信号。当TCP接收端收到了来自网络的拥塞指示后,就设置ECE以便给TCP发送端发送ECN-Echo信号,告诉发送端放慢发送频率。TCP发送端设置CWR,给TCP接收端发送CWR信号,这样接收端就知道发送端已经放慢速率,不必再给发送端发送ECN-Echo信号。
- URG,如果使用了紧急指针就设置这个flag。
- ACK被设置,表示确认号字段是有效的。
- PSH被设置,表示这是被PUSH的数据。特此请求接收端一旦收到数据后立即将数据递交给应用程序,而不是缓冲起来。
- RST用于重置一个已经变得很混乱的连接。
- SYN被用于建立连接过程。在连接请求中,SYN=1和ACK=0;在连接应答中,SYN=1和ACK=1。表示CONNECTION REQUEST和CONNECTION ACCEPTED。
- FIN被设置,表示发送端已经没有数据需要传输了。用来释放一个连接。
- 窗口大小字段指定了从被确认的字节算起可以发送多少个字节。0表示接收端没有空间存放数据了,希望发送端停止发送数据。接收端可以通过发送一个具有同样确认号但是非0窗口大小字段的段来通知发送端继续发送段。
- 校验和。它校验的范围包括头、数据、以及概念性伪头,伪头协议号为TCP(6),校验和必须强制执行。
- 选项字段必须32bits的倍数。
- MSS:允许每台主机指定它愿意接受的最大段长
- Window scale:允许发送端和接收端在连接建立阶段协商窗口尺度因子。双方使用尺度因子将窗口大小字段向左移位最多14bit。因此允许窗口最大可达2**30个字节。
- Timestamp:携带发送端发出的时间戳,并被接收端回应。一旦在连接建立阶段启用了它,那么每个数据包都要包含这个选项。可以用来估计多久之后数据报可以被认为丢失。还可以被用作32位序列号的逻辑扩展,根据时间戳丢弃入境段,从而解决序号回绕的问题。
- SACK(Selective ACK):使得接收端可以告诉发送端已经接收段的序号范围,这是对确认号的补充。
TCP连接建立
TCP使用三次握手来建立连接。
为了建立一个连接,某一段(比如服务器)必须依次执行LISTEN和ACCEPT原语,然后被动地等待入境连接请求。
发送端(比如客户端)执行CONNECT原语,同时说明它希望连接的IP地址和端口号、他愿意接受的最大TCP段长,以及一些可选的用户数据(比如口令)等参数。CONNECT原语发送一个SYN=1,ACK=0的TCP段,然后等待接收端(比如服务器)的响应。
当这个段到大接收端,那里的TCP实体检查是否有一个进程已经等待目标端口字段指定的端口上执行了LISTEN。如果没有,则它发送一个RST=1的应答报文,拒绝客户的连接请求。如果某个进程在该端口监听,如果它接收则发送回一个确认段。
TCP连接释放
为了释放一个连接,任何一方都可以发送一个设置了FIN标志位的TCP段,这表示它已经没有数据要发送了。当FIN段被确认后,这个方向上的连接就被关闭,不再发送任何数据。然而,另一个方向上或许还在继续发送数据。当两个方向都关闭了之后,连接才算彻底释放。所以,通常需要2个FIN段和2个ACK段(但第一个ACK可以和第二个FIN在一个段里)。
虽然TCP通常采用对称释放方式来断开连接,许多Web服务器给客户端发送一个RST段,导致突然关闭连接,这种方式更像非对称释放。Web服务器之所以这么做,是因为它知道数据交换已经结束,所以它可以给客户端发送一个警告,然后骤然关闭连接。如果客户端收到这样的警告,它会释放它的连接状态;如果没收到,最终它也会意识到服务器不再与自己交谈,并释放连接。