UNIX网络编程卷1:套接字联网API-第2章:传输层 TCP/UDP和SCTP

来源:互联网 发布:小说地图制作软件 编辑:程序博客网 时间:2024/05/03 02:56

1.OSI模型

OSI(open systems interconnection)计算机通信开放系统互连模型,是一个七层的理论模型(也就是说理论上分得很细致完善,但实际中设计实现中有出入)

实际过程中我们一般采用网际网协议族

物理层和数据链路层干的事情可以对应为网络硬件和设备驱动程序,如果不是要写驱动程序,一般我们不予关心。

网络层中规定的协议是什么呢? 就是我们经常说的IPV4和IPV6,

传输层中规定的协议是什么呢?TCP/UDP/SCTP,编写网络程序的人主要就是关注这一块 

不通过传输层,直接使用IPV4和IPV6来写网络应用也是可以的,采用原始套接字(raw socket,套接字的一种)可以做到

理论中的会话层/表示层/应用层实际中合并成一层,统称应用层,一些网络应用,包括常见的web浏览器 qq 网易云音乐都是这一层的产物

 我们需要牢牢记住上面的层次结构

2.传输层

    讨论协议,我们可以从它所提供的服务入手

       TCP(传输控制协议)

1.TCP提供客户和服务器之间的连接(connection):
TCP客户先与某个给定服务建立一个连接,再通过这个连接与那个服务器交换数据,然后终止这个连接。再说白话一点,就是tcp客户端和服务器端
建立一个只属于他们自己的通道,他们两个可以借着这个通道相互传东西,但是其他客户端和服务器段无法跨界到这里来。
2.TCP提供可靠性
当TCP向另一端发送数据时,它要求对端返回一个确认。若没有,则自动重传并等待更长时间。数次失败,则放弃并通知。也就是TCP有确认 重传 超时的机制来保证可靠性,此处的可靠性不是说数据100%能传递完全,而是说要么传到了,要么没传到对于我们来说是确认和明确的,没有任何模糊的可能。
3.TCP提供用于动态估算客户和服务器之间的往返时间(RTT)算法
用于知道等待一个确认需要多长时间,会持续估算一个给定连接的RTT
  4.TCP通过给其中每个字节关联一个序列号对所发送的数据进行排序
5.TCP提供流量控制。
TCP总是告知对端在任何时刻它一次能够从对端接受多少字节的数据,这称为对端窗口。借用一下http://blog.csdn.net/hackerwin7/article/details/21969307中的一段话:

TCP是一个滑动窗口协议,即一个TCP连接的发送端在某个时刻能发多少数据是由滑动窗口控制的,而滑动窗口的大小实际上是由两个窗口共同决定的,一个是接收端的通告窗口,这个窗口值在TCP协议头部信息中有,会随着数据的ACK包发送给发送端,这个值表示的是在接收端的TCP协议缓存中还有多少剩余空间,发送端必须保证发送的数据不超过这个剩余空间以免造成缓冲区溢出,这个窗口是接收端用来进行流量限制的,在传输过程中,通告窗口大小与接收端的进程取出数据的快慢有关。另一个窗口是发送端的拥塞窗口(Congestion window),由发送端维护这个值,在协议头部信息中没有,滑动窗口的大小的就是通告窗口和拥塞窗口较小值,所以拥塞窗口也看做是发送端用来进行流量控制的窗口。滑动窗口的左边沿向右移动称为窗口合拢,发生在发送的数据被确认时(此时,表明数据已被接收端收到,不会再被需要重传,可以从发送端的发送缓存中清除了),滑动窗口的右边沿向右移动称为窗口张开,发生在接收进程从接收端协议缓存中取出数据时。随着发送端不断收到的被发送数据的ACK包,根据ACK包中的确认序号和通告窗口大小使滑动窗口得以不断的合拢和张开,形成滑动窗口的向前滑动。如果接收进程一直不取数据,则会出现0窗口现象,即滑动窗口左边沿与右边沿重合,此时窗口大小为0,就无法再发送数据。

下面附一个TCP协议头的格式和滑动窗口的示意图(截自TCPIP协议详解):

 

                                                  图1.TCP头部结构

 

                                                图2.滑动窗口示意图


6.TCP连接是全双工的

意味着在一个给定的连接上应用可以在任何时刻在进出两个方向上既可以发送数据又接收数据。相当于通道被一分为二变成两个子通道,通道数据流方向相反,对于每个子通道TCP都要跟踪诸如序列号和通告窗口大小等状态信息。通过某些手段,可以转换成一个单工连接。

7.TCP是一个字节流(byte-stream),消息无边界,要自行定义规则  


TCP连接的建立和终止(重点来了)


牢牢记住上面的这张图

三路握手过程:(建立)(需要三个分节)

  • 服务器先调用socket创建套接字,调用bind绑定端口,调用listen监听端口(从此句可以看出为什么之前我们运行时间获取客户端程序的时候,需要先确保服务器程序已经运行),调用accept
  • 客户端调用 socket创建客户端套接字,选定一个端口后(一般系统自行选择,也可以认为选择),主动发起连接请求(调用connect),导致客户TCP发送一个SYN(同步)分节给服务器,它告诉服务器客户将在(待建立的)连接中发送的数据的初始序列号。通常SYN分节不携带数据,所在IP数据报只还有一个IP首部,一个TCP首部和可能的TCP选项(记住这个东西,以后很有用)
  • 服务器必须确认(ACK)客户的SYN,自己也得发送一个SYN(其中也包含服务器将在同一分节中发送的数据初始化序列号),服务器将上述作为一个整体分节发送给客户端
  • 客户端ACK服务器的SYN

再看上述图时,要注意三路握手的具体过程分别发生在函数调用的什么时期,三路握手起始于客户connect的主动调用,当connect成功返回时,完成了前两路,并开始第三路,而服务器端在接收到ACK后,会阻塞到read(现在只需要有大致印象,以后详解)


TCP连接终止:(通常需要4个分节)


  • 一般是某个应用进程首先调用close,称该端执行主动关闭。该端的tcp于是发送一个FIN分节,表示数据发送完毕
  • 接收到这个FIN的对端进程将其作为一个文件结束符(放在已排队等候该应用进程接收的任何其他数据之后)
  • 一段时间后,接收到这个文件结束符的进程将调用close关闭它自己的套接字,导致它的tcp也发送一个FIN
  • 原发送端确认这个FIN

特别说明

  • ACK  M+1 和FIN N过程之间可能还有数据的流动(半关闭)(也就是被动关闭进程确认了别人的FIN,发送ACK后,但自己还没有调用close关闭自己的套接字的这段时间)
  • 应用进程调用close主动关闭套接字会使得所在端TCP发送一个FIN。Unix进程调用exit或从main返回,或收到一个终止进程信号,所有打开的描述符都会被关闭(套接字可看成一种特殊的描述符),使得仍然打开的TCP连接上也会发送一个FIN

TCP状态转换图

参见我另一篇博文 tcp状态转换详解

UDP(用户数据报协议)

暂略,持续更新~~

阅读全文
1 0