Linux下的网络基础 学习 Linux 网络编程时我们很快就会遇到socket()、bind()、connect()、send()等接口。如果只是记忆函数功能肯定会有很多疑惑所以写下这些函数之前有几个问题值得先弄明白数据如何跨主机传输程序交给操作系统的数据怎样到达另一台计算机为什么需要多种地址有了 IP 地址为什么还需要 MAC 地址和端口号数据如何找到进程数据到达目标主机后操作系统怎样知道该交给哪个程序这篇文章从一条消息的传输过程出发把网络发展、协议、分层、封装、路由和进程通信串起来为下一篇 Socket 编程建立基础。目录一、计算机网络背景二、协议让双方对字节的含义达成一致三、协议分层把通信问题拆开解决四、封装与分用数据怎样穿过协议栈五、IP 与 MAC最终目的地和当前下一跳一、计算机网络背景计算机发明出来是为了人类服务的人类有信息交换的需求因此不断地探索在计算机层面的数据交换从军用阿帕网到 TCP/IP 协议制定后奠定通信基础再到万维网走向大众。本质就是在把更大范围的机器以更快速的方式连接起来。1. 独立主机每一台独立运行的计算机都可以完成数据的本地处理。2. 局域网LAN局域网通常覆盖家庭、办公室、校园等较小范围。局域网中相当于把多台主机连接在同一个物理链路层上多台设备共享传输介质。共享带来了数据高速传递、延迟低的好处同时也需要解决多台主机同时发送数据时造成的数据冲突。此时交换机发挥了作用交换机将每一个端口独立成一个冲突域通过 MAC 地址表转发实现数据共享。3. 广域网WAN广域网连接更大范围内的网络互联网就是最大的广域网。谈到广域网就不得不聊一下路由器路由器就像不同队伍的传信员承担不同局域网数据传递的工作。了解了路由器的核心功能这里建立一个认识通信双方之间可能隔着多段网络数据需要逐段转发。“广域网”和“局域网”不过就是一个相对的概念。站在数据的角度网络通信可以理解为一个进程通过网络把数据交给另一个进程。二、协议让双方对字节的含义达成一致正如人类必须通过约定俗成的语言才能进行交流一样计算机进行数据交换也存在这样一种机制我们称之为协议。在数据传递的物理层面计算机之间的传输媒介是光信号和电信号通过电平高低和频率来传递 0、1 这样的信息。要想传递各种不同的信息就需要约定好双方的数据格式。但是互联网几乎把全球的主机都连接起来了如果每两台主机间都有自己的数据格式发送给其他主机就是一串乱码。为此权威国际组织制定了一套全球共同遵守的“网络协议”实现了数据在全球范围的流通。协议主要规定以下三方面内容数据格式字节如何组织各字段如何排列。字段含义每个字段代表什么信息。通信行为通信过程中应遵守的规则例如 TCP 的连接建立、确认和重传。从 C 语言的角度可以借助结构体理解协议字段struct message_header { uint32_t length; /* 表示有效数据长度 */ uint8_t type; /* 表示数据类型 */ }; /* ...... */但结构体只是程序内的一种表达方式。实际设计网络协议时还要明确线上每个字节的布局。直接发送整个结构体的内存可能受到填充、对齐和主机字节序的影响接收方也可能使用另一种语言。三、协议分层把通信问题拆开解决前面介绍过了数据通过光电信号在物理层面传递局域网间交换机完成主机间的数据交换功能路由器则实现了局域网间的数据交换。在数据的层层转发中需要考虑怎样在物理层面传递数据怎么在同一局域网间互联的主机间正确传递数据怎么跨局域网在网络上正确传递数据又要怎么处理传递过程中数据错乱丢失。协议分层把这些职责拆开。每一层向上提供服务并使用下一层的能力。这样应用程序通常不必关心底层使用网线、光纤还是无线链路。OSIOpen System Interconnection开放系统互连七层网络模型称为开放式系统互联参考模型是一个逻辑上的定义和规范。TCP/IP 四层模型把数据链路层和物理层相关能力合称为链路层。下表按五层划分梳理各层职责五层划分主要解决的问题典型协议或技术应用层数据表达什么业务含义HTTP、DNS、自定义应用协议传输层怎样在通信端点之间传输数据TCP、UDP网络层怎样寻址并跨网络转发IPv4、IPv6数据链路层怎样在当前链路上传送帧以太网、Wi-Fi 的链路层机制物理层怎样通过介质传递比特电信号、光信号、无线电信号在普通 Linux TCP/UDP 编程中应用协议通常由用户态程序处理TCP/IP 等协议主要由内核处理底层传输由驱动和网卡硬件协作完成。应用通过 Socket 接口使用内核协议栈提供的服务。还要区分两种关系同层之间按协议进行逻辑通信。相邻层之间通过本机接口交付数据。发送方的 TCP 与接收方的 TCP 遵守同一个协议但 TCP 的数据仍然需要经过 IP、链路和实际网络才能到达对方。四、封装与分用数据怎样穿过协议栈1. 封装假设应用生成了一条消息并交给 TCP 发送。为了完成各层的职责协议栈会加入相应的控制信息。下面展示一段应用数据的典型封装关系这一过程称为封装。图中的 FCS 是以太网帧末尾的校验字段因此封装也可能添加尾部信息。关于封装有几个关键概念需要明确报头添加的协议首部结构体。有效载荷payload去掉报头部分后剩下的数据。对某一层来说由它承载的上层数据就是有效载荷例如 IP 层承载的有效载荷可以是整个 TCP 报文段。报头内容通常包含有效载荷长度、报头自身长度、对应协议以及其他重要信息。完整报文在不同层中有独特的叫法所在层报文叫法链路层数据帧网络层数据报传输层数据段2. 分用数据发送时要层层封装最后物理传输到目标主机后上层应用要拿到有效数据会进行一个反过程。数据到达接收主机后协议栈需要逐层检查和解析然后把有效载荷交给合适的上层处理者。这涉及两个动作解封装识别本层控制信息取出有效载荷。分用根据协议字段等信息选择接下来的处理者。应用拿到字节以后还需要按应用协议解析业务消息。学习一种协议时可以先问自己两个问题它怎样区分控制信息和有效载荷它怎样确定有效载荷的下一位处理者五、IP 与 MAC最终目的地和当前下一跳1. MAC 地址用于当前链路的帧交付常见以太网 MAC 地址占 48 位即 6 字节例如08:00:27:03:fb:19。MAC 地址在网卡出厂时就确定了不能修改。MAC 地址通常是唯一的虚拟机中的 MAC 地址不是真实的 MAC 地址可能会冲突也有些网卡支持用户配置 MAC 地址。以太网帧中包含源 MAC 和目的 MAC。发送方需要确定当前这一段链路上帧应该交给谁如果目标在本地链路上目的 MAC 通常是目标接口的 MAC如果需要经网关转发目的 MAC 通常是网关在本地链路上的接口 MAC。IPv4 以太网中主机可以通过 ARP 获取下一跳 IP 对应的 MAC并缓存结果。以太网与交换机的几个要点以太网中通过 MAC 地址判定数据是否发送给自己。以太网中任何时刻只允许一台主机发送数据。多台主机同时发送数据会导致数据错乱称为数据碰撞。数据碰撞本质是因为之前局域网多台主机共用一个总线数据串行传递会发生干扰。交换机通过自学习缓存建立 MAC 表只将数据转发给目的端口相当于给数据交换主机间开通了一个专属会话室提高了效率并避免数据碰撞。2. IP 地址用于网络层寻址IPv4 地址占 32 位即 4 字节通常写成点分十进制形式例如192.168.1.10。每一部分对应一个字节取值范围为 0255。跨网段的主机的数据传输数据从一台计算机到另一台计算机传输过程中要经过一个或多个路由器。假设一种场景主机 A192.168.1.10/24主机 B192.168.1.20/24主机 C192.168.2.20/24/24表示前 24 位为网络前缀对应掩码255.255.255.0。在普通配置下A 到 B 可以在本地链路直接交付正如上面 MAC 介绍A 到 C 则需要经过网关如下图。假设 A 的路由表指向这个网关且不涉及 NAT、隧道等处理传输位置源 IP → 目的 IP源 MAC → 目的 MACA 到路由器A 的 IP → B 的 IPA 的 MAC → R1 的 MAC路由器到 BA 的 IP → B 的 IPR2 的 MAC → B 的 MAC3. IP 在网络宏观传输过程中的作用结合之前涉及到的封装和解封当我们向远在天边的朋友发送消息时数据在主机 A 经过层层封装后以数据帧的形式从网卡发送向路由器路由器解包拿到网络层封装报头中包含的源 IP、目的 IP通过掩码比对后封装并发往下一站通过层层跳转将数据传递到目标主机 B。综上源 IP 记录你最初的出发地目的 IP 指向最终目的地源 MAC 记录数据途径的上一站目的 MAC 指向当前链路上的下一跳。IP 地址在整个路由过程中一直不变目前阶段这样理解。MAC 地址一直在变指向下一个“驿站”。目的 IP是路径选择的重要依据MAC 地址是局域网转发的重要依据。4. 一个生动的类比为了更好理解 IP 和 MAC我们可以举一个生动的例子。《西游记》中唐僧师徒从长安出发前往西天取经唐僧途经车迟国时面对国王会说贫僧从东土大唐而来要前往西天求取真经国王前往西天我们下一站要去哪国王会给唐僧通过文牒并告诉他们下一站是通天河。在这个过程中唐僧向国王这个路由器展示了自己的源 IP长安、目的 IP西天国王的通关文牒就是修饰唐僧的源 MAC通天河就是他们眼下的目的 MAC。浅显理解就是目的 IP 是长远目标而目的 MAC 是阶段性目标当我们达成一个阶段性目标后会制定下一个不断接近长远目标。有了这些基本认识我们后面就能更方便地理解端口、UDP、TCP 协议以及 Socket 相关函数的关联了。