Linux 网络基础概念

在计算机刚出现时,是没有网络这个东西的,信息的传输主要靠的是存储硬件的转移,这当然是不方便的,计算机到底是人的工具,人要协同工作,网络的产生是必然的。

协议

计算机里的协议,哪怕不是学计算机的人,应该也听说过,比如:TCP/IP 协议,HTTP 协议等。但协议究竟是什么东西呢?又是干什么用的呢?举个例子:

一个恶魔把两个人的嘴巴封住,关进不同的房子,他们必须合力解开谜题才能逃出去。A所在的房子里有三个按钮,按正确顺序按下他们获救,B所在房子有正确的顺序,他要把消息传给A。天使提前告诉了他们规则,于是他们商量:我们虽然嘴巴被封住,但是可以通过敲击墙壁传递信息,比如敲一下按第一个按钮,敲两下......当恶魔把他们关起来时,他们利用这个方法成功逃出。

A和B的约定就是协议。

网络的信息传输本质传输的就是01串,对01串的解读可以有多种方法,但是如果用的不是和发出者相同的方法,那么得到的信息就是错误的,所以必须统一解读的方法,也就是网络协议

网络连接整个世界,所以协议也必须用同一套,否则协议就不成协议了,那么谁来定协议呢?当然是业界内有江湖地位的组织了,这个我们不需要太过了解,知道协议是什么和为什么要有协议就够了。

协议分层

协议本质也是软件,为了更好的模块化,解耦合,协议被设计成层状结构。

OSI 是国际标准化组织制定的一套网络分层标准,把两台电脑通信这件复杂事,拆成 7 层分工完成,每层只干自己分内工作,每层有专属协议。

TCP/IP 协议是一组协议的代名词,还包括许多协议,组成了 TCP/IP 协议簇。它采用5层结构,物理层,数据链路层,网络层,传输层,应用层。

搞软件的考虑物理层的比较少,一般只考虑软件相关内容,因此很多时候也直接称为 TCP/IP 四层模型。

即使不是网络,单台计算机内部也是有协议的,所谓协议,就是通信双方都认识的结构化的交互规则,可以理解为一个结构体。

局域网(以 以太网 为例)网络传输流程

每台主机在局域网中,要有一个唯一的标识来保证主机的唯一性,这个标识叫:Mac地址

Mac 地址是网卡出厂时就确定了的,通常是唯一的(虚拟机中的 Mac 地址不是真实的,可能会冲突,而也有些网卡支持用户配置 Mac 地址)。

在以太网中,任何时刻只允许一台机器向网络中发送数据,如果多台同时发送,会发生数据干扰,叫做数据碰撞 。没有交换机(在局域网内把数据精准转发给对应设备的二层网络设备)的情况下,一个以太网就是一个碰撞域。

两台主机发送消息的过程:

其中每一层都是有协议的,所以在传输时要进行封装和解包。

一条完整的数据,除了我们要发送的 "你好" ,即有效载荷 之外,还有有每一层的报头 ,这就是一个报文。而每一层的报文又有其独特的称谓:

跨网络传输流程

上面是在一个局域网内的数据传输流程,而两个局域网也是要进行通信的,它的过程又是如何的呢?

IP地址

IP地址在跨网络传输中用来标识网络中不同主机的地址。

IP协议 有两个版本,IPv4 和 IPv6,IPv4是32位二进制,4段十进制,格式如 192.168.1.1 ,这种十进制也叫做 "点分十进制 " 。IPv6是64位二进制,8段十进制,格式如 1001:0bd8: :1 ,也叫 "冒分十六进制"。

由于IPv4只有32位,总地址上限只有约 43亿,而IP地址又是唯一的,所以 IPv4 的地址其实已经枯竭了,但是 IPv4 和 IPv6又不兼容,所以现在的新设备基本都能跑两套协议。下面的讲解默认是指 IPv6。

跨网段的主机数据传输,数据从一台计算机到另一台计算机的传输过程中要经过一个或多个路由器。

主机发送数据时,先通过 IP (还有子网掩码,但我们今天不考虑太多)判断目标设备是否属于本地局域网,若在同一局域网 :直接通过交换机转发给对方,不经过路由器;若不在同一局域网:数据包发送给内网网关路由器,然后路由器查看目标 IP,查询路由表,把数据转发到下一级中转路由器,层层传递直到抵达目标设备所在局域网。

这时我们会发现 IP 地址和 Mac 地址很相似,但是对于它们的区别现阶段还不好说明,我们可以暂时这样理解:IP 是一种长远目标,而 Mac 是现阶段的下一个目标

我们从网络获取信息,一般都是从网站、软件中获取,这些东西本质不就是进程吗!所以数据数据传输到主机上还没有完,还要再找到特定进程,这时就要用到端口号

端口号

端口号 port 是传输层的协议内容,它是一个 2 字节 16 位整数,一个端口号只能被一个进程占用,用来标识一个进程。

端口号的划分也有点说法。 0 ~ 1023 属于知名端口号 ,是HTTP,SSH等这些广为使用的应用层协议,它们的端口号都是固定的;1024~65535 是系统动态分配的端口号,客户端程序的端口号就是由系统从这个范围分配的。

socket 套接字

IP + port 就能找到唯一一台主机的唯一进程,这就是套接字

网络字节序

之前我们就知道,在内存中的多字节数据相对内存地址有大小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大小端之分,网络数据流同样有。

TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址高字节。

如果发送主机是小端,就需要先将数据转成大端,可以通过调用一些库函数做转换。

cpp 复制代码
#include<arpa/inet.h>

// 主机字节序 → 网络字节序
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);

// 网络字节序 → 主机字节序
uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);

函数名很好记忆:h 表示 host,n 表示 network,l 表示 32 位长整数,s 表示 16 位短整数