前言:网络知识很是的重要,若是你不是作程序的,那么一些网络常识仍是得知道的;而作程序的,就更不用说了,不只须要了解一些网络知识,仍是知道其原理,若是不了解原理,不敢说他不是程序员,可是总缺了点意思,就像去北京没去过长城同样。程序员
网络原理系列文章:浏览器
1、五分钟了解网络链接(已完成)服务器
2、收发数据的原理(上)(已完成)网络
3、收发数据的原理(下)(已完成)并发
4、收发数据的番外篇(未完成)socket
上一篇五分钟了解网络链接讲了网络链接的大概流程,而且文末讲到客户端委托协议栈收发数据能够总结为四步:tcp
一、建立套接字(建立套接字阶段)post
二、将管道链接到服务器端的套接字上(链接阶段)操作系统
三、收发数据(通讯阶段)3d
四、断开管道并删除套接字(断开阶段)
本文会对前两个步骤展开描述,后面两个步骤,下一篇文章介绍,敬请关注!因为网络知识点很是繁杂,读者请沉住气阅读此文,我尽量详细介绍,尽量的不那么枯燥,因此本文介绍也有侧重点。读完本文,你可能会对一些知识恍然大悟,哦,原来是这样啊!好了,废话很少说,直接进入主题。
上面是协议栈的内部结构。分为接个部分。上面部分会向下面的部分委派工做。
应用程序的下面是Socket库,其中包括解析器,解析器向DNS服务器发出查询,它的工做过程咱们在上一篇已经介绍过了。
再下面就是操做系统内部了,其中包括协议栈。协议栈的上半部分有两块,分别是负责用TCP协议收发数据的部分和负责用UDP协议收发数据的部分,它们会接受应用程序的委托执行收发数据的操做。关于TCP和UDP,会在后面文章讲解,目前只要知道像浏览器、邮件等通常的应用程序、QQ文件传输都是使用TCP收发数据的,而像DNS查询、QQ语音 、QQ视频等收发较短的控制数据的时候则使用UDP。
协议栈的下半部分是利用IP协议控制网络包收发数据的部分,在互联网中发送数据,须要将数据分红一个个小的网络包,而后将网络包发送给通讯对象就是由IP负责的。另外,ICMP用于错误提示以及各类控制消息,ARP则是用于查询IP相应的以太网MAC地址。如今只须要大概知道这个名词,后面才会细讲。
IP下面是驱动程序负责控制网卡硬件,最下面的网卡则是负责完成实际的收发操做——对网线中的信号执行发送和接受操做。
实际上套接字并没存在实体,只是一个概念。在协议栈内部有一块存放控制信息的内存空间,用于记录通讯操做的控制信息。好比通讯对象的IP地址、端口号、通讯操做的状态等。因此硬要说套接字是个实体,那就是这些控制信息或者是保存这些控制信息的内存空间。
协议栈执行操做时须要参阅这些控制信息。来决定下一步该作什么。好比:发送数据时,看看IP地址和端口号;发送数据后,协议栈须要等待对方返回数据的响应信息,可是数据可能会半途丢失。咱们不可能一直等待,因此套接字中须要记录是否已经收到或者发送数据了多久,才方便知道是否要重发数据。套接字的控制信息还有不少做用,在此不一一列举了。
协议栈是根据套接字中记录的控制信息工做的。
建立套接字时,须要调用Socket库中的socket组件,注意这里,大写的是Socket,小写是库中的一个程序组件。
应用程序调用socket程序申请建立套接字,而协议栈则根据应用程序的申请执行建立套接字的操做。
在建立过程当中,协议栈会分配一个用于存放套接字所需的内存空间,用于存放记录套接字操做的控制信息。建立套接字时,数据收发操做还没开始,因此把这初始状态的信息存入内存空间中。到此,建立套接字操做完成。
建立套接字,不只要分配空间,并且须要初始化状态信息。
而后,套接字须要将它的描述符告诉应用程序。描述符至关于车库号,告诉我车库号,我才知道哪一个才是我要的车库。一样,描述符是用在应用程序委托协议栈收发数据的时候。套接字包含了通讯对象的信息,好比已经说过的IP地址、端口号,因此应用程序收到套接字的描述符,应用程序再提供给协议栈,协议栈就知道了套接字中所包含的通讯对象信息,就能够准备链接通讯对象了。
由于历史缘由,其实这里的“链接”就更像是通讯前的准备,叫“准备”其实更适合
调用socket程序申请建立完套接字,而后应用程序会调用Socket库的另一个程序组件connect,这样协议栈就会将本地的套接字与服务器的套接字进行链接。这里的链接是指通讯双方交换控制信息,在套接字记录一些必要信息并准备数据收发的一连串操做。
咱们说的链接不是指网线一直插着的链接,不是指通讯过程当中将数据转换成电信号。而是当应用程序委托发送数据时,协议栈经过描述符找到的套接字取得通讯对象的IP地址和端口号等信息。这属于链接操做的目的之一。
说完应用程序,再说下服务器那边,服务器也会建立套接字,可是服务器的协议栈和客户端这边同样,没有相似一个描述符的东西就没办法知道通讯对象,无法开始通讯。因此得有客户端先开始请求,告诉服务器必要信息。好比“我要和你请求,个人IP地址是10.10.1.118,端口号是8900”。因此,应用程序向服务器发送请求,也是链接操做的目的之一。
链接实际上通讯双方交换控制信息,在套接字中记录必要信息并准备数据收发的一连串操做。
控制信息,是控制数据收发操做的一些信息。IP地址、端口号就属于其中的信息。其他的控制信息,咱们后面再介绍。双方经过通讯规则进行信息交换从而完成数据收发准备。收发操做,须要一块临时存放要收发的数据的内存空间,这块内存空间叫作缓冲区,它是在链接操做过程当中分配的。
控制信息能够分为两类。一是客户端和服务器相互联络时交换的控制信息。二是保存在套接字中,用来控制协议栈操做的信息。
第一类:客户端和服务器交换的控制信息,不只是在链接时须要,包括数据收发和断开链接操做在内,整个通讯过程都须要。咱们前面说过,数据会被分红一个个网络包发送,而这些信息就是被添加在客户端与服务器传递的网络包的开头。在链接阶段,因为数据收发尚未开始,网络包中没有实际数据,只有控制信息。这些控制信息位于网络包的开头,所以成为头部。固然,以太网和IP协议也有本身的头部(包含着控制信息),为了不不一样头部混淆,咱们通常记做TCP头部,以太网头部、IP头部。本文主要讲解TCP头部,其他知识后面再讲,读者有兴趣可先自行查阅。
客户端和服务器在通讯中会将必要的信息存放在头部并相互确认。你们如今要知道的就是头部是用来记录和交换控制信息的。
第二类:套接字中的控制信息。这里会保存应用程序传递来的信息以及从通讯对象接收到的信息,还有收发数据操做的执行状态等信息也会保存于此,协议栈根据这些信息来执行每一步操做。
通讯操做中使用的控制信息分为两类: (1)头部中的信息 (2)套接字(协议栈的内存空间)中记录的信息
上面咱们已经介绍了链接(准备)操做的含义,接下来看一下具体操做过程。首先是应用程序调用Socket库中的connect,相似下面👇
connect (<描述符>,<服务器IP地址>,<服务器端口号>,...)
上面的调用提供了服务器的IP地址和端口号,这些信息会传递给协议栈中的TCP模块。TCP模块就会与该IP地址对应的对象,也就是与服务器的TCP模块交换控制信息。
seq:(Sequence Number):本报文段数据的第一个字节的序号 ack:(Acknowledgment Number):确认号——指望收到对方下个报文段的第一个数据字节的序号
控制位包含如下几部分 URG:紧急指针有效位。 SYN:创建链接,当须要创建链接时,他的值为1.即SYN=1 ACK:确认链接,当ACK=1是才有效,ACK=0是此控制位无效。 FIN:断开链接,提出断开链接这一方的值为1. RST:从新创建链接,值为1时表明从新创建链接。 PSH:要求接收方将数据尽快将数据段送达应用层
上图主要介绍了TCP头部。其中TCP头部目前要认知的有发送方和接收方的端口号,序号(seq)是发送方告诉接收方本报文段数据的第一个字节的序号,ack号是接收方告诉发送方已收到了全部数据的第几个字节。其中ack是Acknowledgment Number的缩写。可能读者纳闷IP地址在哪,IP地址其实在IP头部才有。因为本文重点是介绍TCP,因此下方只给出IP头部图,读者自行阅读
应用程序与服务器的TCP模块交换控制信息这一过程包含几个步骤:首先,客户端先建立一个包含表示开始数据收发操做的控制信息的头部(上面所说网络包中开头的控制信息),头部包含不少字段,其中要关注的重点是客户端和服务器的端口号,也就是说,客户端的套接字知道了链接服务器的哪一个套接字。而后,咱们把头部中的控制位的SYN设置为1,你们能够认为它表示链接。此外,还需设置适当的序号和窗口大小。
链接操做的第一步是在TCP模块处建立表示链接控制信息的头部
经过TCP头部中的发送方和接收方的端口号能够找到要链接的套接字
当TCP头部建立好以后,接下来TCP模块会将信息传给IP模块并委托它进行发送。IP模块执行网络包发送操做后,网络包就会经过网络发送到服务器的IP模块,再由服务器的IP模块把接收到的数据传给服务器自身的TCP模块,这时,服务器的TCP模块会根据TCP头部的信息找到端口号对应的套接字,而后套接字就会写入相应的信息,并把状态改为正在链接。
TCP模块、IP模块分别属于网络原理中OSI模型7层结构的传输层、网络层,而传输层处于网络层的上一层,也就是高一层,要完成传送数据,必须从通讯一方的高层传到低层,再经过网络传给通讯另一方的低层,再到那一方的高层完成接收。因此发送数据得从高一层的TCP到低层的IP模块逐一传递。
上述操做完成后,服务器的TCP模块会返回响应,这个过程跟客户端发送数据给服务端同样,须要在TCP头部中设置发送方和接收方端口以及SYN比特。另外,客户端向服务器发送第一个网络包时,因为服务器尚未接受过网络包,因此ACK比特设为0,那么在返回响应就须要将ACK控制位设为1,表示已经收到相应的网络包。网络中常常发生错误,网络包也会丢失。所以通讯双方必须相互确认网络包是否已经送达,通讯双方如何确认?其实就是经过设置ACK。接下来,服务器TCP模块会讲TCP头部传给IP模块,并委托IP模块向客户端返回响应。
而后,网络包就会返回客户端,经过IP模块到达TCP模块,并经过TCP头部信息确认链接服务器的操做是否成功。若是SYN为1,则表示链接成功,这时会向套接字中写入服务器的IP地址、端口号等信息,同时还会将状态改为链接完毕。到这里,客户端的操做就已经完成。但其实还剩下一个步骤,客户端收到数据后,也要像服务器那样把把ACK设置为1,并发回给服务器,告诉服务器,我已经收到服务器发来的响应包,当服务器收到这个返回包后,链接操做才算所有完成。
有没有以为上面的双方相互确认网络包操做,彷佛很熟悉,没错!它其实就是tcp的三次握手。
TCP三次握手 1.A向B发起创建链接请求: 2.B收到A的发送信号,而且向A发送确认信息 3.A收到B的确认信号,而且向B发送确认信号
链接(准备)操做完成后,套接字能够随时进行收发数据了,这个时候咱们能够理解通讯双方已经有一条相连的管道,这条管道链接着双方的套接字。固然这条管道并不真正存在,只是业界为了方便理解,比喻而已。
创建链接后,协议栈的链接操做就结束了。也就是说,当初应用程序调用Socket库中connect程序组件操做已经执行完毕,控制流程又从新交回到客户端。等到后面的收发数据操做。
在此,收发数据的建立套接字阶段、链接阶段已经讲完,剩下的通讯阶段、断开阶段留到下次再讲。网络的东西很枯燥,而且并非那么可视化,学会的要诀是沉住气,看到这里,若是你如今还不能讲到收发数据的前两个步骤,请回到文章顶部,再看一遍。Over and over again,你就会学有所成。
欢迎关注技术公众号「程序员大咖秀」