UDP_第二章 传输层:TCP和UDP
2.1 概述
1) UDP是一个简单、不可靠的数据报协议;
2) TCP是一个复杂、可靠的字节流协议;
2.2 总图
1) IPv4: 32位地址(4X8)
2) IPv6:128位地址(8X16)
3) TCP:传输控制协议; 面向连接、全双工字节流、可靠。TCP 套接字是一种流套接字(SOCK_STREAM), TCP 关心确认、超时、重传等细节以保证数据传输的可靠性;——stream socket;
4) UDP: 用户数据报协议;无连接协议。UDP套接字是一种数据报套接字(SOCK_DGRAM);——datagram socket;
2.3 用户数据报协议(UDP)
1) 应用进程往一个UDP套接字中写入一个消息,这个消息会被封装成UDP数据报,该UDP数据报接着被封装为IP数据报,然后发生到目的地;
2) UDP是不可靠的,不保证数据到达目的地;
3) UDP数据报有一个长度,这个长度随数据一起传递给接收端应用进程;TCP是一个字节流协议, 没有长度、边界;
4) UDP是无连接到, UDP客户与UDP服务之间并不存在长期的连接;一个UDP客户可以创建一个套接字,使用这个公共的套接字将数据发送给多个服务器; 一个UDP服务器可以创建一个套接字,使用这个公共的套接字将数据发送给多个客户;
2.4 传输控制协议 TCP
1) 首先, TCP 先在客户和服务器之间建立连接;然后进行数据传输;最后终止这个连接;
2) TCP 提供可靠的数据传输, TC 发送数据后要求对端给一个确认, 如果没有收到确认, TCP 就自动重传数据并等待更长的时间;数次重传失败后, TCP 才放弃传输(4-10 分钟);
TCP 中的RTT算法动态估算客户和服务器之间的往返时间,以知道发送端等待一个接收端的确认需要多久时间;
3) TCP 对数据分配序号进行排序, 以保证传输可靠性;TCP 将数据分节, 分节是TCP传递给IP层的数据单元;数据在发送端被分解成分节传给IP, 在接收端IP将分节传给TCP协议,组合成原数据;
4) TC P提供流量控制, TCP 总是需要告知在任何时刻它一次能够从对端接受多少字节的数据,即通告窗口;通告窗口指出接收缓冲区当前的可用空间,保证发送端发送的数据不会在接收端溢出;通告窗口动态变化, 接收到数据时候,通告窗口减小;应用程序从TCP缓冲区读取数据时候, 通告窗口变大;当TCP对应的某个套接字的接受缓冲区已满, 此时TCP的就必须等待应用程序从该TCP缓冲区读取数据,才能从对端再接受数据;
5) TCP 是全双工的,TCP 必须为每个数据流方向跟踪诸如***和通告窗口大小等状态信息;例如, 为A>>B流创建***和通告窗口, 为B>>A流创建 ***和通告窗口;
2.6 TCP连接的建立与终止
2.6.1 TCP三路握手
1) 服务器使用socket、bind、listen三个函数使服务器被动打开;
2) 客户调用connect发起主动打开,这导致客户发一个SYN J分节给服务端,J是在待连接中的数据的初始***;该分节不带数据;
3) 服务器应答客户的SYN,同时发送在自己的一个SYN M分节, M是服务器发送数据的初始***;
4) 客户必须确认服务器的SYN;此后,客户与服务器建立连接;
服务器:
socket—— 创建一个监听套接字描述符;
bind——将listenfd绑定到一个socket地址;
listen——在listenfd上面等待客户;
accept——建立与服务器的连接,返回连接套接字描述符connfd;
客户:
socket——创建sockfd
connect——与服务器连接
2.6.2 TCP选项
每一个SYN可以含有多个TCP选项;
1) MSS选项:最大分节大小(maximum segment size),发送SYN的一端通知对端其每个TCP分节愿意接受的最大数据量,发送端的TCP使用接收端的MSS值作为所发送的分节最大大小;(发送端的MSS和接受端的MSS可以不同);TCP_MAXSEG提取和设定MSS值;
2) 窗口规模选项:TCP的一端通知对端的最大窗口大小是65535(2^16). 然而当今互联网高速发送,窗口为65535 已经不满足要求; 窗口规模选项指定窗口必须扩大到级数(左移0-14位),导致最大窗口是1GB;(65535 X 2^14);
在一个TCP连接上使用窗口规模的前提是两个端(发送端、接收端)系统必须都支持这个选项;
3) 时间戳选项, 对于高速网络是必要的,可以防止失而复现的分组可能造成的数据破坏;
2.6.3 TCP连接终止
1) 某个应用进程首先调用close, 主动关闭, 该端的TCP于是发送一个FIN分节,表示数据发送完毕;
2) 对端接收到FIN执行被动关闭;对端的TCP确认FIN, 将其作为一个文件结束符传递给其应用程序。FIN的接收意味着接收端应用进程在相应连接上再无额外数据可以接收;
3) 一段时间后, 接收到这个文件结束符的应用进程将调用close关闭其套接字。这导致他的TCP也发送一个FIN;
4) 接收这个FIN的TCP确认这个FIN;
注意,应用进程调用一个close后,会向对端发出一个FIN; 另外, 当一个UNIX进程无论自愿(exit)还是非自愿终止(接收到终止进程的信号), 所有打开的描述符都会被关闭, 这也使得向对端的TCP发出一个FIN;
通常由客户端执行主动关闭;
2.6.4 TCP 状态转换图
2.6.5 观察分组
建立TCP连接之后, 客户就可以发出数据请求,服务器要做出请求确认并给出数据应答;
当服务器处理请求和数据应答的时间少于200ms的时候, 采用捎带做法,即服务器对客户请求是伴随着数据应答一起的;如果服务器耗时较长去处理数据应答, 那么服务器先发送请求确认,然后进程数据应答;
2.7 TIME_WAIT状态
执行主动关闭的一端会经历TIME_WAIT状态, 该端点停留在这个状态的持续时间是最长分节生命期MSL×2;
TCP为MSL指定一个值;MSL是任何IP数据报在因特网上能存活的最长时间;
理解网络传输中的一个现象:分组在网络中迷途是由于路由异常导致的。某个路由器奔溃或是某两个路由之间某个链路断开, 路由协议需要花费数秒钟或是数分钟时间才能稳定并找出另一条通路。这段时间可能导致路由循环(路由器A将数据发给B,路由器B将数据发送给A);假设一个TCP分节发生迷途,发送端超时并重发这个分节,重发的分节到达接受端, 不久后,迷途的TCP在路由完成修复后也到达目的地。TCP需要处理这个迷途的重复分节;
TIME_WAIT状态存在的两个理由:
1) 可靠的实现TCP全双工链接的终止;
2) 允许老的、迷途的重复分节在网络中消失;
如果TCP打算执行所有必要的工作以彻底终止某个连接上的两个数据流(全双工关闭), 就必须正确处理链接终止序列上的4个分节中任何一个分节丢失的情况;(参考图2-5);
假设ACK N+1 丢失, 客户端就需要等待服务端再一次发送FIN, 如果客户端必须维护状态TIME_WAIT, 允许客户端在再一次接收到FIN之后发生ACK给服务端;
2.9 端口号
端口号是16位的整数:0-65535
当一个客户想要跟一个服务器联系时候, 必须标志想要与之通信的这个服务器(即端口);
客户通常使用临时端口;
1) 众所周知的端口:0-1023,
2) 已登记的端口:1024-49151,
3) 临时端口:49152-65535,
套接字对:
定义连接两个端点的四元组:
(本地IP地址:本地TCP端口号, 外地IP地址:外地TCP端口号);
套接字对是唯一标识网络上每一个TCP连接的标识;
2.10 TCP 端口号与并发服务器
主机是多宿的,说明这个主机具有多个网卡,有多个IP地址;一般是一个网卡连接内网、一个网卡连接外网;
服务器上注意区分监听描socket和连接socket;
当服务器接受一个客户的连接到时候(accept函数), 服务器进程fork一个子进程处理该客户端请求;已连接套接字使用与监听套接字相同的本地端口; 在多宿主服务器上, 套接字的地址一开始时候是通配符*, 连接一旦建立, 已连接套接字的本地地址随即填入;
2.11 缓冲区大小及限制
影响IP数据报大小的限制:
1) IPv4数据报最大大小是65535字节,包括IPv4首部。这是因为IPv4首部中表示数据长度的位置有16位;
2)IPv6数据报最大大小是65535 + 40,其中20字节是IPv6首部。IPv6有一个特大净荷选项,可以扩展数据报大小,但是这个选项使用前提是MTU(maximum transmission unit, 最大传输单元)超过65535的数据链路支持;
3) 许多网络有硬件规定的MTU, 例如以太网的MTU是1500字节;
IPv4要求最小链路MTU是68字节 = 20字节首部+ 48字节选项部分;
IPv6要求最小链路MTU为1280字节;
4) 两个主机之间的路径的最小称为路径MTU, 例如, 1500字节是以太网MTU的常见路径MTU。 两个主机之间相反方向上路径MTU可以不一致, 因为因特网中路由选择往往是不对称的;A>>B的路径可以不同于B>>A的路径;
5)当一个IP数据报从某个接口出去时候, 如果IP数据报的大小超过相应链路MTU, IPv4, IPv6将执行分片, 这些片段在到达最终目的之前通常不会被重组;
注意:
A)IPv4主机对其产生的数据执行分片,IPv4路由器对其转发的数据执行分片;
B)IPv6主机对其数据执行分片, IPv6路由器不对其转发到数据执行分片;但是IPv6路由器对其路由器产生的数据可以执行分片;
6) IPv4首部的DF位(不分片位)可以被设置, 这样该数据一定不会分片, 如果此时数据报大于MTU, 会产生一个错误;
DF位的设置可以用于发现路径MTU, 如果中间路径返回一个错误, TCP就会减少每个数据报的数据量并重发;
(区分数据的分节与数据报的分片):整个数据根据数据报的大小分节成数据报, 数据报根据物理上MTU的大小限制分片成;
7) 最小重组缓冲区大小, 是IPv4和IPv6的任何实现都必须保证支持的最小数据报大小;IPv4 是576字节, IPv6 是1500字节; 我们不能确定目的地址是否支持577字节,但是目的地址一定支持576字节;因此许多使用UDP的IPv4网络避免产生大于576字节的数据报;
8) TCP的最大分节大小 MSS, 向对端通告每个分节中能发送的最大TCP数据量,目的是告诉对端重组缓冲区大小的实际值, 从而试图避免分片。 MSS通常等于MTU-IP首部-TCP首部;
MSS是一个16位的字段,限定最大值是65535, 适用于IPv4, 因为IPv6的最大TCP数据量是65535 - 40;
对于IPv6, 其有特大净荷选项;65535 此时视为一个无限的特殊值,这个值只有在特大净荷选项时才使用, 当接收到对端通告的MSS为65535时候, 那么他所发送的数据大小限制就是接口MTU;
2.11.1 TCP输出
每个TCP套接字有一个发送缓冲区,我们可以使用SO_SNDBUF 套接字选项更改该缓冲区大小。
当某个应用程序调用write的时候, 内核从应用程序缓冲区复制数据到TCP的发送缓冲区, 如果套接字的发送缓冲区容不下应用程序传输过来的数据, 该应用程序就会阻塞, 内核不从write系统调用返回, 直到应用程序缓冲区中的所有数据都复制到TCP的发送缓冲区;
使用write系统调用只能保证数据从应用程序传输到套接字的缓冲区,并不能保证数据已经传输到对端;
之后TCP将TCP缓冲区的数据发送给对端TCP;对端收到数据之后必须发送确认ACK, 本端TCP在收到对端ACK的时候, 才能从TCP缓冲区中丢弃已经确认的数据;
本端TCP以MSS大小或是更小的块把数据传递给IP,同时在每个数据块上安上以ige首部,这样就构成了TCP分节;IP会给每个TCP分节安上一个IP首部以构成IP数据报,并且按照其目的IP地址以确定外出接口,然后将数据报发生给相应的数据链路;
2.11.2 UDP 输出
UDP 套接字没有发送缓冲区,但是可以使用SO_SNDBUF选项更改, 这里SO_SNDBUF仅仅表示这个UDP数据报大小的上限;如果一个应用程序写一个大于套接字发送缓冲区大小的数据报,内核将返回一个EMSGSIZE错误。
UDP是不可靠的, 因此没有必要保存应用程序数据段副本,因此无需真正的发送缓冲区;应用程序的数据在沿协议栈向下传递的时候,会被复制到内核缓冲区中, 然后当数据发送到数据链路层之后,这个数据就丢弃了。TCP中在数据发送出去后,还保存这个数据的副本,知道收到ACK之后, 才丢弃这个副本;
UDP简单地给用户的数据安上8字节的首部以构成UDP数据报,然后传给IP;IP给UDP数据报安上相应的IP首部以构成IP数据报,执行路由操作以确定外出接口, 将IP数据报加入数据链路层的输出队列,或者分片后将每个片段加入数据链路层的输出队列;
从写一个UDP套接字的write系统调用成功返回表示所写的数据报或所有片段已经被加入了数据链路层的输出队列了;