目录
前言:
通过上一篇的学习,我们首先总结一下一些基本的相关结论性的信息
- 对于任何协议来说,它本身都应该拥有把报头和有效载荷进行分离的能力,这是在前面的基础认知中已经有的一个概念,也正是因为有这样的结论,才能做到把数据不断的进行封装传递到另外一个网卡,再不断向上解压缩的过程,这样的结论使得每一层协议实际上看到的内容是一样的,这也是所有操作系统都必须遵循的一个原则。
- 在局域网中,两台主机之间是可以直接进行通信的,那局域网通信的原理就是,每一台主机都有一个属于自己的专属48位的Mac地址,那这个Mac地址本身就是来标记当前主机在局域网的信息,所以在一个局域网中,一个主机想向另外一个目标主机发送一条信息的时候,就必须要面临的问题是,谁发,给谁发的问题,因此就会有根据报头检测,进而对于有效载荷进行分离,把对应的Mac地址进行比对,如果是给自己发的信息就进行保留,如果不是给自己发的信息就进行丢弃,这样就能有效的找到属于自己的包,那这带来的一个结论也是显而易见的,在一个局域网通信的时候,实际上这个包在传递的过程中是所有的主机都是有看到信息的权利的,至于想不想接受是一回事,但是都是可以看到的,所以进而又引出了对于碰撞域的概念理解。
那有了上面的结论,那下面来进入下面的话题,叫做数据的跨网络传输。
一、源IP地址和目的IP地址
首先再次理解什么是IP?
从一个非专业的角度来讲,ip地址通俗来说就是能够保证一个主机在全网的唯一性,这样的描述可能未必正确,但是在绝大多数的情况下是成立的,而ip地址和Mac地址是两个什么概念呢?简单来说,ip地址可以保证的是全网的唯一性,而Mac地址只是运用在局域网中,在局域网中可以保证自己的特定性。(上篇最后的例子唐僧西天取经)ip地址是分为共有ip和私有ip的,那对于公网ip实际上是见到很多次的,例如在Linux的云服务器上就使用过公网ip的概念,那不管怎么说,ip地址都是凸显一个唯一性,而Mac地址会随着所处的局域网的改变而发生改变。
在 IP 数据包头部中 有两个 IP 地址, 分别叫做源 IP 地址 和目的 IP 地址。
如果我们的台式机或者笔记本没有 IP 地址就无法上网,而因为每台主机都有 IP 地址,所以注定了数据从一台主机传输到另一台主机就一定有源 IP 地址和目的 IP 地址,所以在报头中就会包含源 IP 地址和目的 IP 地址。
主流IPV4:
在现在社会,主流的IP地址是IPV4,简单来说就是这个IP地址占用的是四个字节,例如有这种形如192.168.1.2这样的,就叫做是IPV4的IP地址,公网IP能够标识互联网中特定主机的位置,在未来进行传输的过程中,就可以借助这个IP地址在特定的路径中进行转发,进而实现从一个主机到另外一个主机这样的一个过程。
那借助路由器可以实现信息的传递,那具体是如何实现的?我们通过下面的这个图来进行解释:
该路由器具备同时处理以太网和令牌环网协议的能力,能够通过剥离旧协议头部并封装新协议头部的操作实现跨介质数据转发。这种底层网络设备的可扩展性使得上层协议无需关注具体物理传输方式——正如IP网络层仅依赖标准化的包封装格式,无论底层采用何种局域网技术(如以太网帧或令牌环帧),其都会被统一封装为IP数据报进行传输,从而实现了网络层与物理媒介的解耦,凸显了OSI模型中各层独立设计的优势。因此引出这里的下一个结论:
- ip协议屏蔽了底层网络的差异化,靠的就是工作在ip层的路由器
- ip实现了全球主机的软件虚拟层,一切皆是ip报文
于是如果有两个非常远距离的信息,它们是如何进行传递的呢?
如上图所示,借助所处在网络层的路由器,就可以实现远距离传输,当然这中间必然有很多的细节,未来会对这些细节进行阐述。 但是我们将数据从一台主机传递到另一台主机并不是目的,真正通信的其实是应用层上的软件,也就是进程与进程的通信。而我们知道应用层可不止一个软件。既然有了公网 IP 标识了一台唯一的主机,那么数据就可以由一台主机传递到另一台主机。但是有这么多的软件(进程),如何保证软件 A 发送的被软件 B 接收呢?比如说发微信聊天。但是主机怎么知道,你发的这个数据包就是给微信的,而不是给qq的?(用什么来标识主机上的进程的唯一性呢?)那么就要引入一个新的概念了。
二、端口号和进程
这网络通信的事儿,说白了就像两个人打电话——得先有两个人(进程)开机接听才行。你手机想连微信,得先在后台开微信进程;服务器那边也得开着微信服务进程,这样才能聊上。数据传过去的时候,就像快递员送货,得先知道送哪儿(IP地址是小区门牌号),再送到具体哪户人家(端口号相当于房间号)。
整个网络协议栈就像一栋大楼,数据从下往上层层打包。最底下两层(数据链路层和网络层)管怎么把数据从网线传到对面电脑,中间两层(传输层和应用层)才是关键。传输层相当于小区物业,负责根据房间号(端口号)分拣包裹,应用层就是住户自己拆快递。比如说你发条微信消息,微信进程先把消息塞进"TCP"这个快递箱(传输层协议),贴上目标端口号标签,网络层再给箱子套上IP地址外包装,最后通过网卡发出去。
每个手机或电脑里都有个"协议栈大管家",收到数据包先拆开外包装找IP地址,确定是这栋楼后,再根据房间号分发给对应的进程。端口号就是这个房间号,像80端口是给网页服务器的,443是加密网页用的。写代码的时候,服务器得先声明自己监听哪个端口(比如8080),客户端发数据时也要指明要找哪个端口,这样才能准确送达。
整个过程就像快递公司分拣中心:你寄包裹填错小区门牌号就送不到,填错房间号快递员也不知道该给谁。网络通信也是这个理,IP地址保证送到对栋楼,端口号确保送到正确房间,这样才能让微信消息准确跳转到聊天界面,而不是被其他APP误收。
端口号的理解
从代码角度看,端口号本质上是传输层协议(比如TCP/UDP)中的一个两字节数字标识,用来告诉操作系统"这个数据该交给哪个进程处理"。当我们在服务器端用代码绑定一个端口号(比如8080)时,就相当于给这个进程挂了个"通信门牌号"。由于每个主机的IP地址全球唯一,而端口号在同一主机上唯一,组合起来的"IP+端口"就能精准定位到全网某个特定的进程——这就像你家地址(IP)加上房间号(端口),快递员才能准确把外卖送到你桌上。
对客户端而言,只要知道服务端的IP地址和端口号(比如192.168.1.1:80),就等于拿到了对方的"通信暗号"。当客户端程序发起网络请求时,会在数据包里标注目标IP和端口,传输层协议根据这个"暗号",像快递分拣一样把数据递送到对应的进程手里。这种基于IP+端口的通信机制,本质上就是网络世界里的"门牌号系统",我们常说的Socket其实就是对这个"门牌号+地址"的组合命名——就像你给自家门牌号起名叫"小明家",别人只要喊这个名字就知道该往哪里送信了。
为了更方便的对于端口号进行描述,画出下面的这张图:
当用户在抖音客户端(客户端端口4321)请求视频时,数据会从应用层逐层封装:传输层添加源端口4321和目标端口8080的标识,网络层封装抖音服务器的IP地址。数据经物理层传输到服务器后,通过解封装层层剥离,最终由服务器端口8080对应的进程处理。
端口绑定本质是在传输层维护一个哈希表(类似进程控制块PCB指针的映射表),当8080等端口被抖音服务进程占用时,其他进程无法重复绑定。Linux系统中网络被视为特殊文件,数据收发通过文件缓冲区完成:当报文到达端口8080,系统根据哈希表定位到对应进程,将有效载荷存入该进程的网络缓冲区,实现数据读取。整个过程通过"IP+端口"唯一标识两端进程,确保通信精准定向。
进程和端口号的关系
一个进程可以绑定多个端口号(例如Web服务器可同时监听80和443端口),但一个端口号只能被一个进程绑定。当进程绑定多个端口时,它可以通过不同的端口接收不同服务请求;若多个进程绑定同一端口,则会导致哈希表冲突(无法唯一确定目标进程)。
【总结】
端口号和ip地址,都是用来起到一个标识的作用,其中对于端口号来说是用来标识唯一的一个进程,而ip地址是用来标识唯一的一个主机,那么借助这两个信息就可以在偌大的网络系统中找到一个特定的主机上的一个特定的进程,进而进行相关的信息输送或者是数据传递,也就是说,实际未来在进行通信的时候,根本就不是两个主机在进行通信,而是两个主机上的进程在进行通信,网络的本质不也是进程间通信吗?所以只是和原来的不同的是,这两个进程不是在一个主机上的,而是借助网络的力量来做到了把信息从一个主机传递到另外一个主机,并且还能让两个进程看到同一份资源,进而实现了对于通信的功能。