TCP/IP协议大部分是在有线环境下(比如光缆)传输的,所以这可以算是一篇离题作文了……
一、黄昏的清兵卫
推荐一部电影,《黄昏的清兵卫》,讲述的是明治维新前夜一个落魄武士的故事。为了照顾年幼的女儿和生病的妻子,清兵卫从不和同僚应酬,每天都会在黄昏前准时回家,因此得一绰号“黄昏清兵卫”。清贫拮据的生活因为父亲的悉心照料,逐渐有了家的温暖与幸福。
同时“黄昏”既表示清兵卫的绰号,同时也隐喻变革年代,传统的武士阶层的逐渐没落与衰退。
电影的很多细节也可圈可点。例如日本人对儒家文化和《论语》的崇敬,和关系再亲密的朋友交谈提问时也需鞠躬,日本人心中的“尽忠”情结,两次相对真实的日刀对决场面,乡下武士第一次看到枪炮时的惊讶等等。大环境下改革与传统的冲突,偶尔会映射到日常生活中,在平淡如水的日子里,偶尔激起一个小小的涟漪,之后便慢慢扩散消失。
俗话说,饮水思源。在看完这么好的电影之后,我不禁思考,我是怎么下载到这个电影的?不难发现,“迅雷”这个软件起到了重要作用。
迅雷的下载通常有两种方式,一种是利用FTP协议,从拥有此电影的服务器上下载该电影;另外一种是利用p2p协议,从迅雷本身的服务器上将已经下载好的电影传输到我电脑上(由于下载路径以及迅雷本身的巨大带宽优势,基于p2p协议的下载方式速度会远超FTP)。
由于我是卑微的非迅雷会员,也没有从淘宝上买迅雷的账号,同时从下载平均速度来看,我应该是使用了FTP协议的吧……
二、网络模型和网络协议族
上回我们说到,在计算机网络上有很多很多的协议,那么这回我们就得唠唠到底具体有多少种协议了。为了给这些协议分类,我们需要在说这些协议前了解一下互联网的模型。如下图所示:
比较主流的互联网模型有OSI七层模型和TCP/IP四层模型(这我在系列一的文章里面也说过这茬)。OSI的全称是Open System Interconnection,是国际标准化组织ISO提出的一种试图使各种计算机在世界范围内互联的标准框架。而TCP/IP模型是一种更新的,更加简洁的模型。
事实上,TCP/IP模型正在逐渐取代OSI模型,成为使用更加广泛,更加主流的网络模型(思考题:是不是因为这个模型是美国人创立的,所以人家在疯狂推广呢?)。
应用层的协议面向的是用户可见的计算机软件,比如迅雷,比如chrome浏览器,比如QQ等。可以看到,下载电影所使用的协议FTP(文件传输协议)是属于应用层的协议。HTTP协议(超文本传输协议)服务于我们浏览器浏览网页;SMTP协议是用来发邮件的;DNS协议是用来解析域名的,比如找到www.baidu.com对应的是哪个IP地址,就是它的工作;SNMP协议是用来管理网络节点的(我也不知道我在说什么);P2P协议是一种新型的下载协议,火于迅雷。
传输层负责在知道数据传播路径的情况下,保证数据的准确传输。常见的协议有TCP协议和UDP协议。TCP协议具有重传特性,由于误码率的存在,如果数据传输错误,它会要求重传;UDP协议没有这种特性,数据传输错误了就直接丢弃,这么做可以节省网络的带宽。
网络层负责找到数据传输的起点和终点,以及从起点到终点的具体路径。IP协议就是在此。IP协议有v4和v6之分,分别表示32位的IP协议和64位的IP协议,会在后文详细说明。
网络接口层负责统一不同的通信媒介,让它们在上层看来都是一样的。换句话说,网络接口层关心的是点对点的稳定通信。
(基佬紫的颜色真是好看呢)
三、TCP/IP协议
这个协议包含一系列用于处理数据通信的协议,包括用来寻址的网络层协议IP协议和用来传输数据的传输层协议TCP协议,所以叫TCP/IP协议可以说十分应景了。其他的还包括UDP(用户数据包协议),ICMP(因特网消息控制协议),DHCP(动态主机配置协议)等。
3.1 二进制数据
上回我们说到,计算机程序内的数据,包括任何文件,代码,视频,游戏,都是通过二进制存储的。八位的二进制可以存储一个ASCII字符,16位的unicode二进制数字可以存储包括汉字,韩文,日文在内的很多国家语言文字。
对于十进制数而言,他有几位数,就表示他能表示十的几次方个不同的数字,比如十进制的三位数,能表示0~999总共10^3=1000个数。同理,对于二进制数,他有几位数,就表示他能表示二的几次方个不同的数字,比如二进制的三位数,能表示0~7总共2^3=8个数。
出于方便考虑,我们很有必要明确的知道某位数的二进制能够表示多少个数字。比如2位就是4个数字,4位就是16个数字,8位是256个。。。。
另外,一比特(b)表示二进制数的一位,而一字节(B)表示二进制数的八位。所以一字节=8比特(这也是为什么千兆网的理论最高下载速率是125MB/s)。前一两年有个笑话,某电小编在描述5G通信高比特率(1Gbps)的时候,根据此声称一秒能下一部电影,也不知道是真不知道还是哗众取宠。
3.2 IP协议
通常一个协议的报头,可以揭示这个协议的大部分内容和运作机制。IP协议数据包的报头如下所示:
4位的版本号指的是IP协议的版本,目前只有第4版(0100)和第6版(0110)。报头长度指的是数据包除了数据外的IP协议报头的大小。在上图的例子中,报头的长度是6*32位(24字节),所以该字段的值为6。先前可知,4字节最多可以表示16个数字,除去0,最大的数字为15,所以报头最多可以有15*32=480位,总共60字节的长度。多出来的长度通常是在可选项中增加(不过一般的IP报头没有任何可选项,也就是说报头仅有20比特)。
服务类型(Type of Service ,TOS)占了8个比特。前3比特为优先字段,现在已经不用,第8字节保留未用。第4~7比特分别表示延迟,吞吐量,可靠性和花费。当它们取值为1时,分别表示最小时延,最大吞吐量,最高可靠性和最小费用。不同类型的应用层协议需要不同的特性,例如FTP协议要求最大吞吐量,SNMP(网络节点管理)需要最高可靠性。
总长度字段表示整个数据包的字节长度,由于它有16位,所以数据包的理论最大长度位65535字节。由于大部分数据链路层都不支持特别长的IP数据包(上回讲的802.11协议中,最大的数据长度是1500字节左右),所以很需要将IP数据分片。这些分片的数据拥有相同的标识字段。16位的标识字段用来唯一的标识主机发送的每一份数据报。通常每发一份独立报文,标识的值就加1,当标识字段的值位1111111111111111(16个1,也就是65535)的时候,下一个标识为0000000000000001(15个0,1个1)。值得注意的是,标识字段不是排序序号,因为在IP协议是无连接服务,数据可以无序发送,标识只是为了告诉接收方哪几个数据是同一个包。
标志的第一位是保留不用的,第二位表示是否需要分段(0表示可以分段),第三位表示是否是最后一个分段(1表示后续还有分段)。
由于各IP分片到达目的地的顺序可能是无序的,所以需要偏移量来指明该分片在原来数据报中的位置。偏移量的计算方法为已经“装载”好的分片字节数/8。假设我们要传输3800字节的数据,并将其分片为1400,1400,1000三段数据。那么分片1的偏移为0/8=0;分片2的偏移为1400/8=175;分片3的偏移为2800/8=350。13位偏移量的理论最大值为8192,理论最大分片大小为8192*8=65536字节,正好对应了IP报的总长度字段(16位)。
生存期用来设置数据包最多可以经过的路由器数,通常可以设置为32,64,128等。每经过一个路由器,其值减1,直到0时该数据包就会被丢弃。生存期的设置是为了防止某些数据包在网络中由于找不到目的地而反复传递,浪费带宽的情况。
协议字段说明了IP数据包封装的上层协议类型,比如ICMP(1)、IGMP(2) 、TCP(6)、UDP(17)等。头部校验和字段用于检验IP头部的数据正确性。数据的纠错方法是一门专门的学问,这里不作展开。
源IP地址、目标IP地址字段各占32比特。用来标明发送IP数据报文的源主机地址和接收IP报文的目标主机地址。占32位的可选项字段用于定义一些其他选项,比如记录路径,时间戳等,这些选项很少被使用。值得注意的是,可选项字段必须是32位,如果位数不足,需要用0去填充。
3.2.1 ICMP
ICMP协议(InternetControl Message Protocol)用作提高IP数据包交付成功的机会。作为IP层的协议,它可以以IP协议数据报中数据的形式,发送出去。
8位的类型表示不同的情况,常用的类型如下:3是终点不可达;11是时间超过;12是参数问题;5是改变路由;8或0是回送请求或回答;13或14是时间戳请求或回答。
代码位会进一步区分某种类型的几种不同情况。检验和用于检验ICMP的报文。
类型码下方的32位决定了ICMP的报文类型(似乎反过来说也说得通)。ICMP报文的类型分为两种:ICMP差错报告报文和ICMP询问报文。
3.2.2.1 ICMP差错报告报文(56字节)
当检测到IP数据包有错误时,检测到的网络节点会发送ICMP差错报告报文给发送方。
报告的差错共有5种:终点不可达,源点抑制,时间超过,参数问题和改变路由(重定向)。这些问题都是IP数据包在网络漫游寻找目的地时会遇到的问题。
不废话了,上报文。
1、当检测出接收到的IP数据包有问题时(比如生存期归0,该数据包超过了最大路由次数),该网络节点就会启动生成ICMP的程序。
2、首先拷贝有问题的IP数据包的报头和前8个字节,再在头部添加ICMP特有的报头,如上上图所示。
3、由于这个数据是要经过网络的,所以必须在这个数据的头上重新添加一个IP首部。
喏,这就是最终的成品:
3.2.2.1 ICMP询问报文(40字节)
询问报文有两种,回送请求和回答报文(测试主机和目的站是否可以到达及了解有关状态),以及时间戳请求和回答报文(请求某台主机或路由器回答当前的时间和日期)。
询问报文有一个比较常用的例子,那就是ping。 管理员身份打开Windows的cmd窗口,可以测试本地电脑是否能和特定网站建立连接:
ICMP的询问报文格式,目前只能用这个图来表示:
3.2.2 IGMP/ARP
IGMP是Internet Group Management Protocol(互联网管理协议)的简称。其负责组播成员的管理。
ARP是Address Resolution Protocol(地址解析协议)的简称,是根据IP地址获取物理地址的协议。
由于上述两个协议涉及到了组播技术和地址技术,这又是一个大的范畴,这些内容会在本系列(下)下一个推送中说明。
3.3 TCP 协议
TCP协议的作用是保证数据的有效传输
数据的传输需要计算机特定的程序去驱动。比如我在QQ上向小黄鸭发送hello,就借助了QQ这个软件发送到对方的QQ程序中;我在迅雷上下载电影,就是借助了迅雷这个软件,将电影发送到我的资源管理器程序中。在TCP协议中,“特定的程序”用源端口号和目标端口号表示。举个例子,在知道了源的IP地址 1.1.1.1 和目标的IP地址 2.2.2.2(这一步已经由IP报头完成了)前提下,当确定了源端口号A和目标端口号B时,数据可以认为是从1.1.1.1的A程序发送到2.2.2.2的B程序之中。
不难发现,这两个端口号都是16位的,也就是说,TCP协议认为,计算机中运行的进程不会超过65536个,事实上似乎的确如此,以我的电脑为例,也就100多个进程吧。
TCP传送的字节流中每个字节都能按顺序编号。32位的顺序号字段表示本报文发送数据的第一个字节的序号。以下图为例,蓝色的方框表示要传输的数据,方框内白色的字表示数据的大小。第一个数据的顺序号为0,第二个则是300,第三个是500,以此类推。序号确保了TCP传输的有效性。确认号字段表示下一个期望收到的字节序号,比如对于第一个数据而言,确认号应该是300。
头部长度字段表示头部占32比特的述目,由于它是4比特的,所以TCP头部最多可占32*15=480比特的数据。
接下来有6位标志位字段,出于对其考虑,协议在头部长度字段和标志位字段中插入了保留字段,让三者之和为16比特。各标志位如下:URG(紧急指针有效),ACK(确认序列号有效,只有ACK=1时,确认序列号才有效),PSH(接收方应该尽快将这个报文交给应用层),RST(重新连接),SYN(发起一个链接),FIN(释放/删除一个连接)。
窗口大小字段用于网络的流量控制。该值的含义是本机期望一次接收的字节数,理论上限是65535字节。由于它没有定义“一次”到底是多长,所以也无法推测网络的最高速率。网络的网速控制用了一个比较讨巧的方法,当数据传输失败一次后,“网络窗口”就缩小一倍,也就是说数据传输速率缩小一倍。当一段时间内数据没有传输失败时,网络窗口随着时间线性增长。
校验和字段负责对整个TCP报文段,包括TCP头部和TCP数据进行校验(这与IP协议只校验报头正确性有所不同)。
紧急指针是TCP协议中发送端发送紧急数据的一种方式。只有当URG标志位为1时才会启动。还是以上图为例,如果第二个数据包紧急指针有效,且紧急指针为34,那么根据系统优先读取的就是数据中第300+34=334个字节。
选项字段就是那些……平时基本不会用到的字段。
3.4 UDP 协议
相比于TCP,UDP的报头就简单很多了。
源端口号,目标端口号和TCP一样,长度也是一样的,校验和是非必须项,因为就算是出错了也不会让发送端重传……
与TCP尽可能保证数据真实可靠不同,UDP协议追求的是数据的高速率传输。换句话说,TCP保质,UDP保量。
两者由于各自的特性,在应用上有很大差别。TCP协议会使用在文档的传输,敏感信息,金融信息的传输上,因为人们可以忍受此类信息传输速率较慢,但是无法忍受信息出错;UDP适合传输视频,音频,图像之类的数据,比如在看网络电视时,我们不会很在意景色中有一点小小的瑕疵和模糊,打电话时我们也不会因为声音里面有一点杂音就怒摔电话。
3.5 套接字
假如小黄鸭实在是太受欢迎,导致不仅仅是我,世界各地的人民群众都想和小黄鸭聊天,查看小黄鸭的个人主页。但是小黄鸭一个人根本无法处理这么多的信息,于是他想办法将自己的电脑改装成服务器,并且安装了一系列的程序专门分类处理世界各地人民的请求,如下图所示。
可以发现,小黄鸭使用HTTP协议来实现人们对网页的访问请求,用FTP协议实现人们想下载他电脑里文件的请求。操作HTTP协议的程序有80号程序和8080号程序,操控FTP协议的有20号程序和21号程序。
上述过程中的程序序号,在真实的TCP/IP协议中,被称作套接字。套接字包含IP地址和该IP地址内的端口号(也就是程序的序号)。一个套接字对可以唯一的确定互联网网络中每一个TCP连接的双方(客户IP,客户端口,服务器IP,服务器端口)。
这也可以从侧面看出,数据通信的主体,不是计算机与计算机,而是程序与程序。
3.6 三次握手
自古以来,人们对3这个数字就格外的着迷,证据可以看下图:
互联网世界也不例外。程序之间建立连接,需要至少三次通信过程,这三层通信过程,俗称为“三次握手”。网络上有一个非常通俗易懂的例子阐述三次握手的原理。
然而,英俊帅气的21世纪五好青年研究问题时绝不会停留在主观笼统的感受上。如果想要从报文通信机制上了解三次握手的原则,就需要看下图:
第一步:服务器(小黄鸭)自己建立传输控制模块TCB(transmission control block),进入监听模式,等待客户端的链接请求。
第二步:客户端(我)想要联络小黄鸭,也新建一块TCB,并发送一份数据包给小黄鸭,同时进入发送SYN状态。设置标志位SYN=1,同时按照自身情况选择初始顺序号seq=x。值得一提的是,SYN报文不能携带数据,但是需要消耗一个顺序号(这个似乎比较容易理解,如果携带了数据就要消耗更多的顺序号了)。
第三步:小黄鸭收到我的消息后,如果同意连接,就发出确认报文,同时进入接收SYN状态。设置标志位ACK=1,SYN=1,顺序号依情况设置为y,确认号设置为我的下一个数据x+1。同样的,这个报文也无法携带数据。
第四步:我收到确认报文后,还要向小黄鸭发起确认。同样的,设置ACK=1(但是不需要设置SYN位了),同时自己的顺序号是x+1,确认号是y+1。小黄鸭接收后就我们就进入了建立连接状态。这个报文可以携带数据,但是如果不携带数据则不消耗序号。
第五步:愉快的通信。
3.7 四次挥手
《爱情公寓大电影》中,唐悠悠说电影杀青的时候和王传君视频,王传君点播了一首《来不及说再见》。然而在带宽即是资源的网络世界里,是不允许出现来不及说再见的事情的。再见一定要说,而且走之前必须释放资源。
按照惯例先上简单通俗的:
然后再从报文的角度讨论该过程:
第一步:客户端(我)想终止聊天了。于是停止发送数据,并且发送终止报文,进入终止等待1模式。设置标志位FIN=1(终止报文标准),确定当前顺序号为u。同样的,终止报文也不可以发送数据。
第二步:服务器(小黄鸭)收到终止报文,同时发送确认报文,进入关闭等待状态。设置ACK=1,确定当时顺序号为v,确认号为u+1。同时服务器会通知高层应用程序,结束客户端向服务器的单向连接。但是如果服务器还要发送数据,客户端依然会接收。所以这个状态会持续一段时间。
第三步:客户端接收到确认报文后,进入终止等待2状态。
第四步:当小黄鸭发送完数据后,它会再次发送一个终止报文,进入最后确认状态。设置FIN=1,ACK=1,同时确定自己的顺序号w,以及确认号u+1。
第五步:我收到了小黄鸭的终止报文,发送确认报文。设置ACK=1,顺序号为u+1,确认号为w+1。在等待一段时间后(2*MSL)关闭连接,进入关闭状态。MSL是Maximum Segment Lifetime的简称,可以根据不同应用人为设置。2MSL的存在是为了确保服务器收到了客户端发送的确认报文。
第六步:服务器接收到确认报文,进入关闭状态。
可以发现,相比于三次握手环节,由于增加了对未传输数据的处理,挥手需要四次。
四、总结
本文以应用层的FTP协议开头,粗略讲述了计算机网络模型各个层中包含的协议。同时针对TCP/IP协议族,在报文格式,传送机制(套接字,握手协议)上进行了详细的阐述。可以发现TCP/IP协议不是仅仅两个协议,而是许多协议(比如UDP,ICMP,ARP等)的集合。
由于范畴过大,考虑篇幅,笔者水平等问题,笔者无法从设计思想层面做出好的阐释。尽管如此,笔者依旧能在细节处感受到网络设计者的良苦用心。例如设置标志位,利用偏移量等,将大的数据分片化传输,然后在接收端整个,利用的就是“分治”的思想。三次握手协议让人不禁想到困扰计算机界的“两将军问题”(请自行百度,该问题已经被证明无解),等等。