通俗易懂网络协议(TCP/IP概述)

"\u003Cdiv\u003E\u003Cp class=\"ql-align-justify\"\u003E近期工作,跟网络协议相关,这让我有机会更深入学习网络协议,而之前很长一段时间,我对网络协议的理解都停留在比较浅的层面。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E比如:TCP是面向连接的、可靠传输,而UDP是非连接的、不可靠传输,TCP建连需要3次握手,会造成delay,UDP更快。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E比如:socket编程,服务器socket create、bind、listen、accept、read\u002Fwrite、shutdown\u002Fclose,客户端socket create、connect、read\u002Fwrite、shutdown\u002Fclose,再加上epoll\u002Fselect这几下子。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E再比如:我知道网络编程要忽视SIGPIPE信号不然会挂,read返回0代表对端主动关闭,非阻塞的read要放在循环里要考虑返回值,多路复用以及阻塞、非阻塞的区别。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FUDP的区别上,我是这样理解的:从北京到杭州,TCP相当于修了一条高铁线路(建连)再通车发货(传输数据),而UDP相当于寄快递,丢了不管(直接传输数据)。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E上面的理解对不对?可以说对,也可以说不对。对于应用程序员来说,有了上面的认识+熟悉socket编程接口,够了吗?不够吗?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E大物理学家费曼提出一个高效的\u003Cstrong\u003E费曼学习法\u003C\u002Fstrong\u003E,即从问题入手,试着把问题都讲出来,\u003Cstrong\u003E以教代学\u003C\u002Fstrong\u003E,一旦你能把问题都讲清楚,便学会了。所以我想尝试一下把TCP\u002FIP讲清楚,借此让自己学明白,顺便帮助一下读者。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E虽然《TCP\u002FIP详解卷1》是一本关于互联网协议族很\u003Cstrong\u003E严谨详尽\u003C\u002Fstrong\u003E的书,但在我看来,它稍微有点晦涩,可能需要读几遍,才能心领神会。虽然我没有能力把这个问题说的更好,但因为我经历过从稀里糊涂到稍有所悟的过程,这可能是大师不可比的,我将尽量用通俗易懂的语言把TCP\u002FIP相关的知识讲清楚。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003ETCP\u002FIP是什么\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FIP协议族是一组协议的集合,也叫\u003Cstrong\u003E互联网协议族\u003C\u002Fstrong\u003E,\u003Cstrong\u003E用来实现互联网上主机之间的相互通信\u003C\u002Fstrong\u003E。TCP和IP只是其中的2个协议,也是很重要的2个协议,所以用TCP\u002FIP来命名这个互联网协议族,实际上,它还包括其他协议,比如UDP、ICMP、IGMP、ARP\u002FRARP等。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E网络分层\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E大学《计算机网络》教科书上有经典的网络ISO七层模型,但七层划分太细了,稍显繁琐,不容易记住。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E互联网协议族TCP\u002FIP按粗粒度的\u003Cstrong\u003E四层\u003C\u002Fstrong\u003E划分,两种划分的对照图让彼此关系一目了然。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002F457ebb7141584994bcb2b292cfa21c0f\" img_width=\"423\" img_height=\"240\" alt=\"通俗易懂网络协议(TCP\u002FIP概述)\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E分层\u003C\u002Fstrong\u003E是计算机领域的常用技巧,比如互联网后端的三层架构“接入-逻辑-存储”就是分层思想的典型应用。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E\u003Cstrong\u003E分层是为了隔离\u003C\u002Fstrong\u003E,通过分层划分职能,拆解问题,层与层之间约定接口,屏蔽实现细节。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FIP自下到上划分为链路层、网络层、传输层、应用层。\u003Cstrong\u003E下层向上层提供能力,上层利用下层的能力提供更高的抽象\u003C\u002Fstrong\u003E。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E1. \u003Cstrong\u003E链路层\u003C\u002Fstrong\u003E,也称网络接口层,包括操作系统的设备驱动程序和网卡,它们一起处理与传输媒介(光纤等)的物理接口细节。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E2. \u003Cstrong\u003E网络层\u003C\u002Fstrong\u003E,也就是IP层,负责处理IP datagram在网络中的传输,IP层传输的是IP datagram,借助路由表,把IP datagram从网络的一端传输到另一端,简而言之:\u003Cstrong\u003EIP实现包的路由传输\u003C\u002Fstrong\u003E,IP协议和路由器工作在网络层。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E3. \u003Cstrong\u003E传输层\u003C\u002Fstrong\u003E,提供\u003Cstrong\u003E端到端之间的通信\u003C\u002Fstrong\u003E,包括提供面向连接和高可靠性的TCP,以及无连接不可靠的UDP。貌似TCP更好,但实际不是这样,UDP因为不需要建连开销,所以更快,应用得也很广,比如新一代互联网协议HTTP3就从TCP转向UDP,应根据适应场景选择传输层协议。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E4. \u003Cstrong\u003E应用层\u003C\u002Fstrong\u003E,跟应用相关,不同应用解决不同问题,需要不同的应用层协议。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002Fa2c324bf7a75497abfb45a8149ef2fd6\" img_width=\"1032\" img_height=\"658\" alt=\"通俗易懂网络协议(TCP\u002FIP概述)\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E链路层处理数据在媒介上的传输,以及主机与网卡、光纤等打交道的细节。因为与硬件相关,所以需要借助系统的驱动程序,链路层协议就是定义这些细节的,比如怎么把数据从网卡发送到光纤,采用什么格式编码等,它解决的数据在媒介上表示、流动的问题。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E光有链路层功能肯定是不够的,网络上有成千上万的机器,主机A与B通信,你不能将数据发到主机C,所以仿照现实,要为主机分配网络地址,通过IP地址去标识网络中的一台主机,发送一个数据包,需要正确路由到目的地,这就好比你从家到公司,要经过哪些路径,需要地图,而路由表就类似这张地图。IP解决的是数据包在网络中的传输路由的问题。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E有了网络层的传输路由能力,还不够,因为IP报在传输过程中可能丢包,比如中间经历过的路由器缓冲区满了便会丢包,这样不可靠,如果需要\u003Cstrong\u003E可靠传输\u003C\u002Fstrong\u003E的能力,便需要传输层基于IP层,提供更多的能力,TCP解决了可靠性问题。具体而言,如果丢包了,TCP层会负责超时重传,它\u003Cstrong\u003E通过接收确认和重传机制保证了可靠传输\u003C\u002Fstrong\u003E。另外,因为IP报都是独立路由的,所以从主机A到主机B,一份数据被拆分成x、y两个IP报先后发送,这2个包可能选择不同的传输路径,这样有可能y包先于x包到达,但我们希望在接收端(主机B)恢复这个数据的信息,但我们无法控制IP报的到达顺序,所以,我们需要在接收端恢复数据,我只需要在x、y包里记录它属于数据块的哪个部分,然后重组这份数据,这正是TCP做的,它会重新组装IP报,从而保证\u003Cstrong\u003E顺序性\u003C\u002Fstrong\u003E,递交给应用层。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E有时候并不需要保证可靠性和顺序性,这便是UDP能提供的,它只是简单的把数据封装成IP报,然后通过IP层路由发送到目的端。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E再往上,便是应用层协议了,比如http,又比如游戏服务器自定义协议,应用层协议通常基于TCP或者UDP做传输。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E分层\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E什么是\u003Cstrong\u003E协议?\u003C\u002Fstrong\u003E懒得去翻协议的各种权威定义了,我认为协议就是约定,跟现实生活中协议这个词含义差不多。\u003Cstrong\u003E网络协议就是通信双方共同遵守的约定\u003C\u002Fstrong\u003E,更具体一点,就是定义数据在网络上传输的格式、规则和流程。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E因为网络是分层模型,不同层有不同层的作用,所以为各层定义各层的规则,各层对应的各层协议。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E前面讲了TCP\u002FIP协议族包含很多协议,这些协议分属不同的分层,承担不同的作用。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002Ff24347bb6b7f448181ed3986a9158cf8\" img_width=\"870\" img_height=\"908\" alt=\"通俗易懂网络协议(TCP\u002FIP概述)\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli class=\"ql-align-justify\"\u003ETCP和UDP是两种主要的传输层协议。\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003EIP是网络层的主要协议,TCP、UDP都需要利用IP协议进行数据传输。\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003EICMP是互联网控制报文协议,是IP的附属协议,IP层用它来与其他主机或路由器交换错误报文和其他重要信息。比如一个Packet经过某个路由器节点的时候,超过网络对Packet的长度限制,而又不分片,则会给发送端发送一个ICMP包报告错误信息,属于ICMP是用来辅助IP完成数据包传输的。\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003EIGMP是Internet组管理协议,用来把一个包多播到多个主机。\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003EARP(地址解析协议)和RARP(逆地址解析协议)是用来转换IP层和链路层的地址,IP层使用IP地址,链路层使用Mac地址\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp class=\"ql-align-justify\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E应用层和传输层使用端到端(end-to-end)协议,网络层提供的是逐跳(hop-by-hop)协议。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E封装\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003EA给B通过网络传送一块数据,可以设想仅仅是传输这块原始数据是不够的,因为网络传输过程中,网络包到了某个路由器,需要转发,而转发必须依赖数据包的一些附加信息,比如目标机器。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E发送端在发送数据的时候,将原始数据按照协议格式加上一些控制信息,包装成可在网络上正确传输数据包的过程叫封装。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FIP协议族是\u003Cstrong\u003E层层封装\u003C\u002Fstrong\u003E的,从应用层到链路层,每经过一层都要添加一些额外信息(首、尾部)。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp3.pstatp.com\u002Flarge\u002Fpgc-image\u002Fc3a969824ea149318f23add364e9defe\" img_width=\"484\" img_height=\"360\" alt=\"通俗易懂网络协议(TCP\u002FIP概述)\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli class=\"ql-align-justify\"\u003E用户数据经过应用程序加上应用程序首部,转给TCP层处理\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003E经过TCP层加上TCP首部,产生TCP段(segment)\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003ETCP segment经过IP层再加上IP首部,产生IP数据包(datagram)\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003EIP datagram通过链路层,经以太网驱动程序处理后,加上以太网首部+尾部,产生以太网帧(frame),以太网帧的长度在46~1500之间\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp class=\"ql-align-justify\"\u003E更准确的说,在IP和链路层传输的数据单元叫分组(Packet),分组既可以是一个IP datagram也可以是IP datagram的一个分片(fragment)。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EUDP的封装跟TCP略有不同,主要体现在经过传输层(UDP)之后添加的是8字节UDP首部,产生UDP datagram。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E\u003Cstrong\u003E封装过程中,经过TCP\u002FUDP层的时候,会把端口号添加到TCP\u002FUDP首部;经过IP层的时候,会把协议类型(TCP or UDP or ICMP or IGMP)添加到IP首部;经过链路层的时候,会把帧类型(IP or ARP or RARP)添加到以太网首部\u003C\u002Fstrong\u003E。这些信息将被用于接收端的处理。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E接收端收到数据后,要执行跟发送端\u003Cstrong\u003E相反\u003C\u002Fstrong\u003E的解封操作,我们可以把发送端的数据封装比喻成洗澡后一层层穿衣服,而接收端的操作,类似洗澡前一层层脱衣服,把首尾部剥离,获取传递的原始数据。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E因为网络上的主机有不同字节序,现在要通过网络传输,便需要约定统一的\u003Cstrong\u003E网络字节序\u003C\u002Fstrong\u003E(大端序),采用小端序的主机在网络传输数据的时候要转为大端序。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E地址\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E互联网上每个接口都有一个唯一的网络地址,也叫IP地址,IP地址有IPv4和IPv6两个版本,IPv4是32位4字节的整数,每个字节(8bit)的取值范围是0~255,所以可以把4字节的IPv4用四个点分隔的byte值表示,比如140.252.13.88,每个十进制数值对应32位整数中的每个字节,这种表示法叫\u003Cstrong\u003E点分十进制\u003C\u002Fstrong\u003E表示法,很显然,点分十进制法和int32两种表示法之间很容易相互转换。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EIPv4地址划分为ABCDE五类,32位地址表示的数值空间有限,难以为互联网上的所有联网设备分配独立的IP地址,所以便存在动态分配、共享、公网+内网地址转化(NAT)等问题,本质上是为了\u003Cstrong\u003E解决IP地址不够用的问题\u003C\u002Fstrong\u003E。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EIPv6使用128bit,2的128次方就非常大了,号称可以为地球上每粒沙子分配一个ip地址。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EIP数据报(网络层)用IP地址、而以太网帧(链路层)则是用硬件(48位Mac)地址,ARP和RARP用于IP地址和硬件地址之间做映射(转换)。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E端口\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FUDP采用16位\u003Cstrong\u003E端口号来识别(区分)应用\u003C\u002Fstrong\u003E,比如主机A向主机B发送了一个IP报,主机B的内核收到该IP报之后,应该交给哪个应用程序去处理呢?端口号就是用来干这个的,内核会维护端口号到应用程序之间的对应关系。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E比较常用的应用层协议有约定的端口号,也就是知名端口号,而1024~5000之间的端口号是分配给TCP\u002FIP临时用的,而大于5000的另做他用。也就是说,你用TCP方式去连网络服务器,本地为该socket分配的端口号会在1024~5000之间,这取决于操作系统的端口分配策略。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E域名系统\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E域名系统(DNS)提供主机名字和IP地址之间的转换,比如www.baidu.com是一个域名,应用程序可以通过一个标准库函数(gethostbyname)来获得给定名字主机的IP地址,标准库函数(gethostbyaddr)实现逆操作。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003Eip地址是一串数字,含义不清、也不便于记忆,\u003Cstrong\u003E主机名含义更清晰\u003C\u002Fstrong\u003E,www.baidu.com你就很容易记住,这也是为什么存在IP地址还需要主机名的原因。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E分用\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E接收端接收到以太网数据帧(Frame)之后,需要像\u003Cstrong\u003E剥洋葱\u003C\u002Fstrong\u003E一样,从协议栈由底向上升,即遵照链路层->网络层->传输层->应用层的顺序,去掉各层协议添加的首尾部,将数据取出,交给最上层应用程序,这个过程叫Demultiplexing,尊从书本的翻译叫\u003Cstrong\u003E分用\u003C\u002Fstrong\u003E。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002F1bd03acd8cc84dc59408acc856a3c1bc\" img_width=\"1080\" img_height=\"724\" alt=\"通俗易懂网络协议(TCP\u002FIP概述)\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp class=\"ql-align-center\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E回顾前面封装的描述,在传输层、网络层、链路层,分别将端口号存入TCP\u002FIP首部,将协议类型存入IP首部,将帧类型存入以太网帧首部。所以在接收端,将一层层拆掉首部,取出对应信息,然后做分派,丢给不同模块处理,上图就是整个处理过程。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E小结\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E本文讲了地址、域名、端口、TCP\u002FIP分层模型、封装、分用等概念。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E你最好能记住TCP\u002FIP链路层->网络层->传输层->应用层的四层划分。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP segment、UDP datagram、IP datagram、IP fragment、以太网frame、以及IP层和链路层之间传输的数据单元packet,这些概念你最好分清楚,这样交谈的时候会显得比较专业而不是很土。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E数据封装,多看几遍你便能记住了。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP封装格式:以太网首部(14)+IP首部(20)+TCP首部(20)+应用数据+以太网尾部(4)\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EUDP封装格式:以太网首部(14)+IP首部(20)+UDP首部(8)+应用数据+以太网尾部(4)\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E应用层协议在应用层实现,而传输层、网络层、链路层都是在内核实现,所以想修改或者优化底层协议很难,因为你几乎动不了内核,因为网络上的大量设备OS你没法一并改过来,这就是所谓的\u003Cstrong\u003E网络设备僵化问题\u003C\u002Fstrong\u003E,HTTP3用UDP替代TCP,就是想在应用层自己去实现可靠传输等。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E每个以太网帧有长度限制(48~1500),网络上每个设备也有对包的长度限制,IP报大了就要分片,分片可能发生在发送端,也有可能发生在中间设备,但应该尽量避免分片,IP报会带有信息让分片后可以重组,MTU的概念可以了解一下。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003EICMP和IGMP逻辑上属于网络层,因为他们是IP协议的附属协议,但实际上,\u003Cstrong\u003EICMP和IGMP报文都被封装为IP datagram传输\u003C\u002Fstrong\u003E,所以又可以把他们视为IP层之上的协议。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E同样ARP和RARP用于IP地址和硬件MAC地址相互转换,逻辑上属于链路层,但实际上\u003Cstrong\u003Earp和rarp报文跟IP datagram一样,都被封装成以太网Frame传输\u003C\u002Fstrong\u003E。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E接收端收到以太网帧之后,会走分用流程,最终将原始数据交给应用程序。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003ETCP\u002FIP协议的应用程序经常使用socket编程接口。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E有很多跟网络相关的工具,比如ping、ifconfig、netstat、arp、tcpdump、wireshark等。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E问题\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp class=\"ql-align-justify\"\u003E一年前,我对网络编程这块,脑子里充满疑问。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E众所周知,TCP建连三次握手和断连四次握手,但如前所述,任何时候,从主机A都可以任意发一个IP报到主机B,网络主机之间是通过IP层实现路由转发的,两点之间的每个IP报都是独立路由的,既然这样,为什么还要建连?还要浪费时间做A->B、B->A、A->B来回?直接把包发过去不就完了吗?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E假设通过AB建立的3个IP报的作用是表示AB之间的网络连通性?哪又有什么作用?因为网络是随时变化的,此刻连通又不代表下一刻连通。建连之后似乎并不存在AB之间的真正连接,只是两端OS层面维护的一个状态(数据对象)?是虚拟连接?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E建连到底是什么意思?客户端发送一个IP报到服务器去发起连接?那跟传输数据的普通IP报又有什么区别?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E双工是什么意思?为什么socket关闭一半传输之后就不能发送数据了?网络上IP报不是可以任意传输吗?这个限制是哪个地方添加的?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E拥塞控制是什么?Nagle是什么?滑动窗口是什么?TCP为什么要保活?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003Esocekt的编程接口和各种概念跟TCP\u002FIP原理有怎样的对应关系?学完TCP\u002FIP原理对理解socket编程有什么帮助?\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E没有深究TCP\u002FIP原理之前,我其实是有很多问题的,只是做应用程序开发,好像没搞懂那些问题也还可以凑合干,但终究是有点糊里糊涂,感觉不太爽。\u003C\u002Fp\u003E\u003Cp class=\"ql-align-justify\"\u003E本来我想一篇文章讲清楚TCP\u002FIP的主要内容,但是写着写着发现,这样文章会非常长,所以我决定多写几篇,每篇都讲清楚一个主题。\u003C\u002Fp\u003E\u003Ch1 class=\"ql-align-justify\"\u003E\u003Cstrong\u003E后续计划\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Col\u003E\u003Cli class=\"ql-align-justify\"\u003E协议格式\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003ETCP、UDP的区别,建连、拥塞控制,面向连接和可靠传输到底是什么含义?基于UDP编程怎么实现可靠传输?\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003E编程接口:socket TCP\u002FUDP编程\u003C\u002Fli\u003E\u003Cli class=\"ql-align-justify\"\u003E互联网应用层协议:http、http2、http3(quic)\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003C\u002Fdiv\u003E"
发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();