掘金 后端 ( ) • 2024-05-07 13:43

后端小老板在给他的大哥讲解项目问题,突然问了一句:你知道回环地址吗?

周围安静了一分钟,这沉默震耳欲聋

别问我~

别问我~

别问我~

引言

在当今数字化的世界里,网络通信充当了无数设备和服务之间交互的基础架构。无论是浏览网页、发送电子邮件、进行视频会议还是使用各种云服务,所有这些活动都依赖于稳定且高效的网络通信。网络接口和IP地址是这一复杂系统中的关键组成部分,它们确保数据能够准确无误地从一个设备传输到另一个设备。

网络接口的重要性

网络接口是任何网络通信活动的出发点和终点。它可以是物理的,如以太网接口,也可以是逻辑的,如软件定义的虚拟接口。网络接口的主要功能是提供一个通信端点,设备通过这个端点发送和接收数据。每个接口都有一个或多个与之关联的IP地址,这些地址用于在网络中唯一标识接口。

对于网络技术人员来说,了解和管理网络接口意味着能够控制数据如何进入和离开计算机或网络设备。这包括配置网络安全设置、优化数据流量、故障排除以及维护网络性能。

IP地址的核心作用

IP地址是互联网协议(Internet Protocol,简称IP)的核心组成部分,它为设备在网络中的位置提供了数字标识。每个通过网络发送的数据包都包含源IP地址和目的IP地址,确保信息能够正确送达目标。IP地址不仅帮助路由数据,还可以用来实施安全策略、进行网络管理和优化网络性能。

IPv4和IPv6是目前最常用的两种IP地址版本,它们各自有不同的地址结构和功能。随着互联网设备数量的激增,IPv6的重要性日益凸显,因为它提供了比IPv4更多的地址空间和更先进的网络功能。

为何网络技术人员必须精通这些知识

对网络技术人员而言,精通网络接口和IP地址的知识不仅是基本职责,更是确保网络安全、可靠和高效的关键。通过深入理解这些基础设施的工作原理,技术人员能够更好地设计、优化和保护网络环境,应对日益复杂的网络挑战。此外,随着越来越多的业务和生活活动依赖于网络,网络技术人员的角色变得更加重要,他们的工作直接影响到组织的运营效率和安全性。

综上所述,网络接口和IP地址是网络通信的基石,对它们的深入了解对于任何希望在信息技术领域中取得成功的专业人士来说都是必不可少的。接下来的章节将详细探讨这些组件的技术细节和实际应用,为读者提供必要的知识和技能。

网络接口基础

网络接口是计算机网络中的一个关键概念,它充当着计算机设备与外部网络之间的桥梁。在本节中,我们将探讨网络接口的基本功能以及特别关注回环接口的作用和重要性。

网络接口的功能

网络接口可以是物理的也可以是逻辑的。物理接口指的是实际的硬件设备,例如以太网卡、无线网卡或光纤适配器,它们提供硬件级的连接到外部网络。逻辑接口则是通过软件创建的,如虚拟网络接口和VPN端点,它们在软件层面上模拟物理连接的功能。

无论是物理的还是逻辑的,网络接口的主要功能包括:

  1. 数据发送与接收:网络接口负责将数据包发送到网络,并从网络接收数据包。
  2. 地址分配:每个网络接口都会被分配一个或多个IP地址,这些地址在网络中唯一标识该接口。
  3. 数据流控制:网络接口根据需要管理数据的流量和速度,确保数据传输的效率和稳定性。

回环接口(Loopback Interface)

回环接口是一种特殊的网络接口,它在计算机内部虚拟化,并不与任何物理网络设备直接连接。它通常被分配一个特定的IP地址,最常见的是IPv4环境中的127.0.0.1或IPv6中的::1。回环接口的主要作用和特点包括:

  1. 网络软件测试:开发者利用回环接口测试网络软件或网络配置,无需实际的物理网络连接。这使得测试过程更为简便和快捷。
  2. 系统自检和配置:系统和应用程序可以通过回环地址测试自身的网络功能,确保软件组件能够正确处理网络数据。
  3. 安全隔离:由于回环交通不离开主机,它为运行在本地的服务提供了一个安全的通信环境,不受外部网络的直接影响。

回环接口的一个典型应用是在开发阶段,软件开发人员经常使用它来运行和测试服务器应用程序,如Web服务器和数据库服务器,这些程序配置为监听回环地址,从而仅允许本地访问。

总之网络接口是连接计算机设备与网络的关键元素,而回环接口则提供了一个重要的内部测试和通信机制。理解这些接口的工作原理对于网络管理和优化至关重要,特别是在进行网络配置和故障排查时。通过有效管理网络接口,技术人员可以确保数据的正确流动和网络的最优性能。

回环地址和localhost的区别

在讨论网络通信时,回环地址和localhost是两个经常被提及的概念。虽然它们经常被互换使用,但在技术上有细微的区别和不同的应用场景。

回环地址127.0.0.1的技术含义和用途

回环地址,特别是127.0.0.1,是为IPv4配置的特殊网络地址。它是在RFC 5735中定义的,专门用于指向执行网络操作的本机。这意味着当一个程序尝试连接到127.0.0.1时,它实际上是在尝试与同一台计算机上的一个服务进行通信,而不是外部的一个设备。

用途包括:

  • 软件开发和测试:开发者可以在不影响外部网络的情况下,在本机上测试网络应用。
  • 服务配置:系统管理员可以配置服务只监听回环地址,从而限制服务只能从同一台机器上访问,增强安全性。
  • 网络教学和实验:教育者和学生可以使用回环地址进行网络协议或网络程序的实验,无需实际的网络硬件。

localhost作为默认的计算机自引用地址的配置

localhost是一个主机名,用于指向本机的回环接口。默认情况下,localhost会解析为回环地址127.0.0.1,在IPv6中则是::1。这是通过操作系统的主机文件(如Unix/Linux中的/etc/hosts或Windows中的%SystemRoot%\System32\drivers\etc\hosts)进行配置的。

配置的目的是:

  • 提供一个常用的、易记的名称代替数字IP地址。
  • 允许开发人员和系统管理员在编写脚本或配置文件时使用localhost,而不必担心具体的IP地址。

网络安全应用和潜在的安全隐患

安全应用:

  • 隔离和保护:通过配置服务仅在回环地址上监听,可以防止外部访问,从而保护服务不受未授权访问。
  • 安全测试:安全专家可以在本机上安全地测试恶意软件或开发防御策略,不会影响到网络上的其他设备。

潜在的安全隐患:

  • 误配置:如果服务错误地配置为在localhost上监听,但实际需要在网络中提供服务,可能导致服务无法被外部访问。
  • 漏洞利用:攻击者可能利用运行在localhost上的服务的漏洞进行攻击,尤其是如果这些服务未正确配置或更新。
  • 跨站请求伪造(CSRF):如果Web应用不正确地配置,攻击者可能构造请求,利用用户的浏览器访问运行在localhost的服务,进行恶意操作。

总之,虽然127.0.0.1localhost通常用于相似的上下文中,它们在技术上分别指的是IP地址和主机名。理解它们的区别和各自的安全影响对于确保网络和系统安全至关重要。

IP地址的版本:IPv4与IPv6

互联网协议(IP)地址是网络上每个设备的唯一标识符。随着互联网的快速发展,原有的IPv4协议逐渐显示出容量不足的问题,这促使了IPv6的发展和逐步推广。以下是IPv4和IPv6的主要技术特点和优势的对比。

IPv4的技术特点和优势

  • 地址格式:IPv4地址由32位二进制数构成,通常表示为四个十进制数(每个数0-255),通过点分隔,如192.168.1.1。
  • 地址空间:IPv4提供约43亿个唯一地址,这在互联网早期看似足够,但随着设备数量的增加,这一容量已不足以满足全球需求。
  • 配置简便:由于其历史悠久,许多网络设备和软件默认支持IPv4,使得配置和管理相对简单。
  • 技术成熟:IPv4技术非常成熟,有广泛的支持和大量的文档资源。

IPv6的技术特点和优势

  • 地址格式:IPv6地址由128位二进制数构成,通常表示为八组四个十六进制数,通过冒号分隔,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。
  • 巨大的地址空间:IPv6的设计提供了几乎无限的地址空间,理论上可以分配约$3.4 \times 10^{38}$个唯一地址,远远超过IPv4。
  • 自动配置能力:IPv6支持更先进的自动地址配置(如SLAAC),无需手动配置或额外的地址配置协议。
  • 网络层安全性:IPv6设计时考虑了安全性,原生支持IPsec,有助于提高数据传输的安全性。
  • 更有效的路由和数据包处理:IPv6简化了路由器的处理过程,提高了效率,并减少了网络延迟。
  • 无需NAT:由于地址数量充足,不需要网络地址转换(NAT)来共享公共地址,每个设备可以拥有一个或多个独立的全球唯一地址,这简化了网络管理和提高了端到端连接的效率。

为什么IPv6越来越重要

随着设备数量的激增,包括智能手机、平板电脑、家庭自动化设备以及数量庞大的物联网设备,IPv4地址的限制已经成为网络发展的一个瓶颈。以下是IPv6变得越来越重要的几个原因:

  1. 地址耗尽:IPv4地址已基本耗尽,新的网络服务和设备需要更多的IP地址。
  2. 物联网的发展:物联网设备需要大量的IP地址,而IPv4无法满足这一需求。
  3. 网络简化:IPv6使得每个设备都可以直接在互联网上公开其地址,简化了网络结构,提高了效率。
  4. 增强的服务质量(QoS):IPv6更好地支持服务质量,对于数据流量的优先级和安全性有更好的原生支持。

总之,IPv6不仅解决了地址耗尽的问题,还提供了更高效、更安全且更易于管理的网络架构。随着全球对于IPv6的逐步过渡,掌握其特点和优势对于未来的网络管理和配置至关重要。

IPv4地址的数值格式和逻辑结构

IPv4地址由32位二进制数构成,通常分为四个八位(一个字节)的段,每个段转换为十进制数,然后用点(.)分隔。例如,192.168.1.1是一个典型的IPv4地址,其中19216811分别是四个八位字节的十进制表示。

这32位不仅仅是随机分配的数字,它们被分为两个主要部分:网络部分和主机部分。网络部分标识特定的网络,而主机部分标识该网络上的特定设备。这种分割由子网掩码决定,子网掩码是一种指示网络地址与主机地址分界的方式。

公网地址和内网地址

在讨论IPv4地址时,区分公网地址和内网地址非常重要,因为它们各自承担着不同的角色以适应互联网和内部网络的需求。

公网地址(Public IP Addresses)

公网地址是指在全球互联网上唯一标识一个设备的IP地址。这些地址由互联网号码分配机构(如ICANN的下属机构IANA和各地区的网络信息中心,例如APNIC、ARIN、RIPE NCC等)管理和分配。公网地址必须在全球范围内保持唯一,以确保互联网上的设备可以互相识别和通信。

用途:

  • 外部访问:公网地址用于互联网上的服务器、路由器或其他设备,使它们可以被全球的互联网用户访问。
  • 互联网通信:任何需要直接接入互联网并与外部世界通信的设备都需要公网地址。

内网地址(Private IP Addresses)

内网地址是在私有网络内部使用的IP地址,它们不是全球唯一的,也不直接暴露在互联网上。内网地址由组织内部自行管理,不需要经过全球的IP地址管理机构。这些地址的范围已被IANA明确指定,专门用于组织内部网络,通过网络地址转换(NAT)技术与互联网通信。

定义的私有地址范围:

  • 10.0.0.0 - 10.255.255.255(10/8前缀)
  • 172.16.0.0 - 172.31.255.255(172.16/12前缀)
  • 192.168.0.0 - 192.168.255.255(192.168/16前缀)

用途:

  • 内部网络:内网地址用于组织的内部网络设备,如公司电脑、打印机等。
  • 资源共享和通信:内网地址允许内部网络中的设备相互通信和共享资源,而无需使用公网资源。

为什么需要内网地址?

由于IPv4地址的有限性,如果每个设备都分配一个公网地址,那么地址将很快耗尽。使用内网地址可以有效地节省公网地址资源,因为许多设备无需直接接入互联网。此外,使用内网地址还可以增强网络安全,因为内网设备不直接暴露在互联网上,降低了被外部攻击的风险。

网络地址转换(NAT)

网络地址转换是一种网络技术,用于在私有网络和公网之间转换地址。这意味着多个设备可以共享一个公网地址,每当内部设备需要与外部世界通信时,NAT设备会将内部的私有地址转换为公网地址,从而实现通信。这样做既保护了内网的安全,也节约了公网地址资源。

NAT网关在各大公有云都用相关产品(最起码阿里云有,其他的截止发文前没注意)有兴趣的可以去他们官网看看 2024年05月07日13:16:40

综上所述,公网地址和内网地址各自承担着不同的功能,是网络设计中不可或缺的组成部分,它们共同保证了网络通信的效率和安全性。

使用 ip addr 命令查看网络接口信息

ip addr 是一个在Linux操作系统中用于查看和管理网络接口(NICs)的命令。这个命令不仅显示每个网络接口的IP地址,还提供了关于链路状态、MTU(最大传输单元)、广播地址等的详细信息。

在不同操作系统中使用 ip addr

  • Linux: 在Linux终端中直接输入 ip addrip address 来执行此命令。这是最常见的使用场景,因为 ip 命令是Linux特有的。
  • Windows: Windows不使用 ip addr 命令。相应的命令是 ipconfig 或更高级的 Get-NetIPAddress PowerShell命令。
  • macOS: macOS也不使用 ip addr,而是使用 ifconfig 命令,尽管在新版本中 ifconfig 正逐步被 ip 命令取代。

解析 ip addr 命令的输出

输出如下

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

2: enpxx: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.xx.xx.xx/24 brd 172.xx.xx.255 scope global dynamic noprefixroute enpxx
       valid_lft 86153sec preferred_lft 86153sec
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

3: enxxx: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff

4: wlo1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    altname wlp0s20f3

5: br-xxxxxx: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.xx.0.1/16 brd 172.xx.255.255 scope global br-xxxxxx
       valid_lft forever preferred_lft forever

6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.xx.0.1/16 brd 172.xx.255.255 scope global docker0
       valid_lft forever preferred_lft forever

7: utun: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 9000 qdisc mq state UNKNOWN group default qlen 500
    link/none 
    inet 198.xx.0.1/16 scope global utun
       valid_lft forever preferred_lft forever
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

解释一下

1: lo (Loopback Interface)

  • LOOPBACK,UP,LOWER_UP: 表示这是一个回环接口,且处于激活状态。
  • mtu 65536: 最大传输单元为65536字节。
  • state UNKNOWN: 接口状态未知,通常表示没有问题。
  • inet 127.0.0.1/8: IPv4回环地址,掩码为8位。
  • inet6 ::1/128: IPv6回环地址。
  • valid_lft forever preferred_lft forever: 表示这个地址永久有效。

2: enpxx (Ethernet Interface)

  • BROADCAST,MULTICAST,UP,LOWER_UP: 支持广播和多播,接口已激活。
  • mtu 1500: 标准以太网MTU。
  • state UP: 接口处于激活状态。
  • inet 172.xx.xx.xx/24: 私有IPv4地址,子网掩码为24位。
  • inet6 fe80::xxxx:xxxx:xxxx:xxxx/64: 链路本地IPv6地址。
  • dynamic: 表示IPv4地址是通过DHCP动态分配的。
  • noprefixroute: 不自动添加路由前缀。

3: enxxx (Another Ethernet Interface)

  • NO-CARRIER: 表示没有物理连接。
  • state DOWN: 接口未激活。

4: wlo1 (Wireless Interface)

  • state DOWN: 无线接口未激活。

5: br-xxxxxx (Bridge Interface)

  • NO-CARRIER,UP: 虽然标记为UP,但没有载波信号,可能没有连接设备。
  • inet 172.xx.0.1/16: 桥接接口的私有IPv4地址。
  • scope global: 地址具有全局范围。

6: docker0 (Docker Bridge Interface)

  • state DOWN: Docker网络接口未激活,但配置了IP。
  • inet 172.xx.0.1/16: Docker使用的默认桥接网络地址。

7: utun (Tunnel Interface)

  • POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP: 点对点接口,支持多播,无ARP。
  • inet 198.xx.0.1/16: 隧道接口的公网IPv4地址。
  • inet6 fe80::xxxx:xxxx:xxxx:xxxx/64: IPv6链路本地地址。

使用Node.js和TypeScript获取当前网络环境下的所有IP地址

在Node.js中,可以使用内置的 os 模块来获取网络接口及其相关的IP地址信息。这个模块提供了一个非常有用的函数 os.networkInterfaces(),它返回系统上所有配置的网络接口的信息。这些信息可以用来获取关于每个网络接口的详细数据,包括IP地址、子网掩码、MAC地址、是否为内部地址等。

介绍 os 库和 networkInterfaces

os 模块是Node.js的核心模块之一,提供了一些基本的系统操作功能。networkInterfacesos 模块中的一个函数,它返回一个对象,其中包含了主机上每个网络接口的详细信息。这些信息是以接口名称作为键,接口信息数组作为值的形式组织的。

每个接口信息数组中的对象包括:

  • address: IP地址。
  • netmask: 网络掩码。
  • family: IP协议版本(IPv4或IPv6)。
  • mac: 硬件MAC地址。
  • internal: 布尔值,如果接口是系统内部使用的(如回环接口),则为true。
  • cidr: 包含CIDR块的字符串,例如 192.168.1.101/24

示例代码:获取当前网络环境下所有IP地址

下面的示例代码展示了如何使用Node.js和TypeScript来获取当前网络环境下的所有IP地址。代码中定义了两个函数:flattenIPAddressescreateIPDictionary。这两个函数都使用了 os.networkInterfaces() 来获取和处理网络接口数据。

  • flattenIPAddresses 函数返回一个数组,包含所有符合筛选条件的IP地址信息。
  • createIPDictionary 函数返回一个字典,以IP地址为键,包含相应的详细信息。
import * as os from 'os'

interface IPAddress {
  interfaceName: string
  address: string
  family: string
  mac: string
  internal: boolean
  cidr: string | null
}

/**
 * 根据筛选条件和接口名称展平网络接口地址。
 * @param {Partial<os.NetworkInterfaceInfo>} option - 筛选条件,只包含符合这些条件的IP地址。
 * @param {string[] | null} interfaceNames - 可选,仅包含这些接口名称的IP地址。
 * @returns {IPAddress[]} 返回一个包含所有符合条件的IP地址信息的数组。
 */
function flattenIPAddresses(
  option: Partial<os.NetworkInterfaceInfo> = {},
  interfaceNames: string[] | null = null
): IPAddress[] {
  const networkInterfaces = os.networkInterfaces()
  const flatAddresses: IPAddress[] = []

  // 遍历每个网络接口
  for (const interfaceName in networkInterfaces) {
    const addresses = networkInterfaces[interfaceName]

    // 检查接口名称是否在提供的列表中,如果没有提供列表则默认通过
    const interfaceNameFilter = interfaceNames
      ? interfaceNames.includes(interfaceName)
      : true

    // 遍历每个接口下的地址信息
    addresses?.forEach((address) => {
      // 检查当前地址是否符合所有提供的筛选条件
      const isMatch = Object.entries(option).every(([key, value]) => {
        return address[key as keyof os.NetworkInterfaceInfo] === value
      })

      // 如果符合筛选条件,则添加到结果数组中
      if (isMatch && interfaceNameFilter) {
        flatAddresses.push({
          interfaceName,
          address: address.address,
          family: address.family,
          mac: address.mac,
          internal: address.internal,
          cidr: address.cidr
        })
      }
    })
  }
  return flatAddresses
}

/**
 * 根据提供的筛选条件创建一个IP地址字典。
 * @param {Partial<os.NetworkInterfaceInfo>} option - 筛选条件,只包含符合这些条件的IP地址。
 * @param {string[] | null} interfaceNames - 可选,仅包含这些接口名称的IP地址。
 * @returns {Record<string, IPAddress>} 以IP地址为键的字典。
 */
function createIPDictionary(
  option: Partial<os.NetworkInterfaceInfo> = {},
  interfaceNames: string[] | null = null
): Record<string, IPAddress> {
  const networkInterfaces = os.networkInterfaces()
  const ipDict: Record<string, IPAddress> = {}

  // 遍历每个网络接口
  for (const interfaceName in networkInterfaces) {
    const addresses = networkInterfaces[interfaceName]

    // 遍历每个接口下的地址信息
    addresses?.forEach((address) => {
      // 检查当前地址是否符合所有提供的筛选条件
      const isMatch = Object.entries(option).every(([key, value]) => {
        return address[key as keyof os.NetworkInterfaceInfo] === value
      })

      // 检查接口名称是否在提供的列表中,如果没有提供列表则默认通过
      const interfaceNameFilter = interfaceNames
        ? interfaceNames.includes(interfaceName)
        : true

      // 如果符合筛选条件,则添加到结果字典中
      if (isMatch && interfaceNameFilter) {
        ipDict[address.address] = {
          interfaceName,
          address: address.address,
          family: address.family,
          mac: address.mac,
          internal: address.internal,
          cidr: address.cidr
        }
      }
    })
  }
  return ipDict
}

export { flattenIPAddresses, createIPDictionary }

使用createIPDictionary方法改造fastify启动函数

import fastify from 'fastify'
import { getConfig } from './config'
import logger from './logger'
import errorHandlerPlugin from './plugins/error-handler-plugin'
import initWebSocket from './websockets'
import { createIPDictionary } from './pkg/ip'

// 创建 Fastify 应用实例,启用内置的日志记录功能
const app = fastify({
  logger: true
})

// 定义一个异步函数来启动服务器
const startServer = async () => {
  const startTime = Date.now() // 记录开始启动服务器的时间

  try {
    // 定义根路由,当访问 '/' 时返回 { hello: 'world' }
    app.get('/', async () => {
      return { hello: 'world' }
    })

    // 注册自定义的错误处理插件
    await errorHandlerPlugin(app)

    // 使用WebSocket函数初始化WebSocket支持
    initWebSocket(app)

    // 从配置中获取应用程序信息
    const APP_INFO = getConfig('APP')
    // 启动服务器,监听配置中指定的端口和主机
    await app.listen({ port: APP_INFO.port, host: APP_INFO.host })

    const endTime = Date.now() // 记录服务器启动完成的时间
    const startupTime = (endTime - startTime) / 1000 // 计算服务器启动耗时(秒)

    // 记录启动耗时到日志
    logger.info(`Server started in ${startupTime} seconds.`)
    // 这里开始新增--------------------------------------
    const ipDict = createIPDictionary({
      family: 'IPv4'
    })
    // 打印启动地址
    Object.keys(ipDict).forEach((key) => {
      // 记录启动信息到日志
      logger.info(
        `Starting ${APP_INFO.name} server on http://${key}:${APP_INFO.port}`
      )
    })
    // 这里结束新增--------------------------------------
    logger.info(
      `Starting ${APP_INFO.name} server on http://localhost:${APP_INFO.port}`
    )
  } catch (err) {
    // 如果启动过程中发生错误,则记录错误信息并退出进程
    app.log.error(err)
    process.exit(1)
  }
}

export { startServer }

效果

[13:01:41.477] INFO: websocket 初始化成功
[13:01:41.479] INFO: Server started in 0.013 seconds.
[13:01:41.480] INFO: Starting user-hub server on http://127.0.0.1:3588
[13:01:41.480] INFO: Starting user-hub server on http://172.21.10.10:3588
[13:01:41.480] INFO: Starting user-hub server on http://172.16.30.197:3588
[13:01:41.480] INFO: Starting user-hub server on http://198.18.0.1:3588
[13:01:41.480] INFO: Starting user-hub server on http://localhost:3588
[13:01:41.480] INFO: Server started successfully.

写在最后

在这篇综合性的文章中,我们深入探讨了网络接口和IP地址的重要性,以及如何在Node.js环境中利用os模块来获取和管理网络接口信息。此外,实际代码示例和命令行工具的使用展示了如何在实际环境中应用这些理论知识,为技术人员提供了实用的工具和方法来管理和监控网络状态。