使用IPython下的Net-SNMP来管理类UNIX系统的教程

发表于 5年以前  | 总阅读数:281 次

引言

对于简单网络管理协议 (SNMP),大多数系统管理员都具有一定的使用经验,或者至少听说过它。如果您正在一个数据中心工作,那么您每天都可能采用某种方式与 SNMP 进行交互。有许多给人印象深刻的、同等规模的网络管理系统 (NMS) 或者网络监视系统使用了 SNMP 监视,但本文并不打算介绍这些系统。本文主要涉及的是通过 Python? 语言来研究 SNMP,并亲自编写相关的代码。

一位朋友最近告诉我,有时候遇到的情况就像:只是希望沿着街道一路走到奶奶家,而不需要乘坐像 Saturn V 火箭一样飞快。有许多任务,如果利用或者配置大规模的 NMS,就好像是一个 Saturn V 火箭,在填满液氧罐之前,先尝试一下使用 Python,那么您将得到更好的服务。了解如何编写灵活的 Python 代码与 SNMP 进行交互,这可能是系统管理员可以获得的、最有趣且最高效的技能之一。尽管 SNMP 的设置和使用非常复杂,但本文中所讨论的内容将使它变得非常有趣。
安装和配置 Net-SNMP

要学习本文中的内容,您需要在您的 *nix 计算机中安装最新的 Python(即 Python 2.3 或者更高版本)。在撰写本文时,Python 2.5.1 是 Python 的最新版本。您还需要 IPython,以便以交互的方式使用带 Python 绑定的 Net-SNMP 库。Net-SNMP 团队对各种操作系统中的支持进行了详细测试,具体包括 AIX?、HP-UX?、GNU/Linux? 分发版(如 Red Hat)、Windows?,甚至 OS X?。

安装 IPython 是一项非常简单的工作。一个很好的选择是使用 Easy Install 来管理 Python 包。通过运行 ez_setup.py 脚本,您可以很容易地安装任何 Python 包。例如,您只需要键入以下命令:


    easy_install ipython

其他可选的安装方式包括,使用您最喜欢的包管理系统、或者只需下载 IPython 并键入以下命令:


    python setup.py install

请注意,干线 (trunk) 指的是版本控制系统中的根路径,其中保存了最近的代码副本。此外,干线还常常表示一个子版本和版本控制系统。有关更详细的内容,请参见参考资料部分中的子版本链接。

要学习本文中的内容,您需要确保您的客户端计算机、或者运行所有代码的计算机都安装了 NET-SNMP Version 5.4.x 或者更高版本,因为从这个源代码版本开始,包括了 Python 绑定。在大多数情况下,绑定的安装需要对源文件进行编译;然而,也可以使用 Red Hat Package Managers (RPM)。如果你有兴趣和时间,那么可以从 Net-SNMP Web 站点查看一下它的最新版本。

有许多编译选项可供使用,但主要的任务是对 NET-SNMP 进行正确编译,然后运行 Python 目录中的、独立的 Python 安装程序。另一个需要注意的问题是,当您进行编译并运行 ./configure 的时候,它将运行本地计算机(正在编译代理的计算机)的配置脚本。您不应该使用该配置脚本,对于本文而言,您只需要创建一个简单的配置脚本。

对 /etc/snmp/snmpd.conf 中所存储的配置文件进行备份,并构建下面这个非常基本的配置:


    syslocation "My Local Machine"
    syscontact me@localhost.com
    rocommunity public

保存它,并重新启动 snmpd 守护进程。在大多数 *nix 系统中,可以使用 /etc/init.d/snmpd restart 来完成这项工作。

除非在不得已的情况下,否则最好不要对处于活动开发阶段的版本进行编译,因为这样做,您将需要自己动手修复有问题的代码。在 CentOS 5 或者 Red Hat Enterprise Linux 5 (RHEL 5) 中,您可以下载最新的、稳定的源文件 RPM(在撰写本文之时,是 5.4.1 版本)。请注意,您还需要使用 Python 源文件来构建绑定。因此,如果您正在使用一台基于 Red Hat 的计算机,那么请确保为特定的 *nix 操作系统安装了 python-dev(或者其等价物)和 Python Header 文件。如果您在从源文件构建 RPM 的过程中,需要任何帮助的话,请参考官方的 Red Hat 文档。从源文件构建包可能是一个非常复杂的主题,并且已经超出了本文的范围。如果您在使用 Python 绑定的时候遇到了麻烦,那么您应该在 Net-SNMP 邮件列表中请求帮助。
对代码进行分析

还等什么呢?假设您已经安装了 Python 绑定和 IPython。现在,您已经做好了使用 IPython 的准备,并开始相关的工作。尽管在某些时候,您可能还需要浏览 IPython 文档。Jeff Rush 是当前的 Python Advocacy Coordinator,他为 IPython 提供了一些非常好的屏幕录像内容。好的,让我们开始进行编码。

让我们进行一次简单的查询,以便通过使用计算机的对象标识符 (OID) 值 sysDescr 来标识一台计算机。通过键入 ipython 启动 IPython,然后执行这个交互式会话:
清单 1. IPython 示例


     In [1]: import netsnmp

        In [2]: oid = netsnmp.Varbind('sysDescr')

        In [3]: result = netsnmp.snmpwalk(oid,
        ...:             Version = 2,
        ...:             DestHost="localhost",
        ...:             Community="public")

        In [4]: result = netsnmp.snmpwalk(oid,
                    Version = 2,
                    DestHost="localhost",
                    Community="public")

        In [16]: result
        Out[16]: ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 
        18:58:54 EDT 2007 i686',)

请注意,您所得到的 result 值与这里所显示的 result 值是不同的。如果您已经遵循了上面清单 1 中所显示的配置,那么所有其他的内容都应该是可用的。如果您对 SNMP 比较熟悉,那么您可能马上就能够明白这些内容的实际作用。

使用 IPython 来测试 SNMP 代码片段的好处之一是,它就好像是一个普通的 Shell,并且许多基本的、交互式 Shell 的概念"都可以起作用",但需要说明的是,它们是以 python 方式进行工作的。编写 SNMP 代码可能是一项非常单调乏味的活动,但是通过 IPython 来使用 Net-SNMP 库将使其变得非常有趣。

正如您所看到的,要将结果转换为 Python 数据类型,这项任务是非常简单的。这就是为什么 IPython 和 Net-SNMP 可以很好地在一起工作的原因。现在,对于编写自定义脚本来说,只需要以交互方式分析 OID 的组合以进行查询。在理想的情况下,需要运行一个大规模的、易于配置的 NMS 设置脚本,自动地将新的计算机集成到网络中。

当然,并不存在这种理想的情况,您需要了解如何将一些好的 SNMP 代码组合到一起,对于一名系统管理员来说,这是非常有用的。下面给出一个示例情况,假设您刚刚将一个高速 DDR 转换为正在运行 Ubuntu Linux 的 2 TB RAID 0 服务器,因为您必须在一个小时的时间内解决问题,所以您不得不这样做。

现在,您遇到了很大的麻烦,并且您只有几分钟的时间来监视具体的问题,以了解是否需要开始发送简历、或者是否应该开始准备讲话并请求升职。让我们使用 IPython 中的编辑功能来编写脚本,并将它保存到文件中,然后在不离开 IPython 的情况下,在一个会话中运行它: ed snmpinput.py
清单 2. IPython 模块的创建


    import netsnmp

    class snmpSessionBaseClass(object):
      """A Base Class For a SNMP Session"""
      def __init__(self,
            oid="sysDescr",
            Version=2,
            DestHost="localhost",
            Community="public"):

        self.oid = oid
        self.Version = Version
        self.DestHost = DestHost
        self.Community = Community


      def query(self):
        """Creates SNMP query session"""
        try:
          result = netsnmp.snmpwalk(self.oid,
                      Version = self.Version,
                      DestHost = self.DestHost,
                      Community = self.Community)
        except:
          import sys
          print sys.exc_info()
          result = None

        return result

对 IPython 进行自定义以使用正确的编辑器

通过编辑 $HOME/.ipython/ipythonrc,您可以对 Ipython 进行自定义。首先需要进行自定义的内容之一是 %edit 命令,可以通过键入 ed 来调用该命令。在缺省情况下,它被设置为使用 vi,但是您可以更改它,以便使用其他编辑器,包括 Emacs。关于如何更改您的环境,本文给出了相应的指导。您还可以使用下面的命令来启动 Ipython,以便以硬编码的形式指定使用某个特定的编辑器: ipython -editor=vim。

继续执行,将下面的代码剪切并粘贴到您刚刚创建的文件中。当保存这个文件时,IPython 将自动地运行它,并将该类放置到您环境中相应的模块中。如果您键入 who,那么您将看到与以下所示类似的内容:


    In [2]: who
    netsnmp snmpSessionBaseClass

这项操作的功能非常强大,因为您可以获得使用您最喜欢的文本编辑器(也许是 Vim 或者 Emacs)的所有优点,然后在交互的 IPython Shell 会话中立即使用这些代码。请注意,如果您已经编写了一个模块,那么您还可以简单地键入并运行它,以获得相同的结果。执行和运行 IPython 中的模块,这就相当于运行其中的代码,并将其放入到 IPython 环境中。
以迭代的方式进行编码

现在通过使用 IPython,可以将 Python Shell、UNIX Shell 和您最喜欢的文本编辑器的最佳特性组合到一起。在与像 SNMP 库这样非常复杂的对象进行交互时,您需要使用可以获得的所有帮助,而在这个示例中,真正地展示了 IPython 的强大功能。

您可以动态地编写一些模块,并且您可以在稍后对其进行测试和使用。IPython 可以与任何编程风格很好地融合在一起,包括测试驱动的开发 (TDD) 或者测试增强的开发 (TED)。为了证明这种便利性,让我们转到您刚刚编写的模块。

既然已经有一个面向对象的 SNMP 接口,那么您就可以开始向本地计算机进行询问:
清单 3. IPython 迭代式编码


    In [1]: run snmpinput

    In [2]: who
    netsnmp snmpSessionBaseClass  

    In [3]: s = snmpSessionBaseClass()

    In [4]: s.query()
    Out[4]: ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686',)

    In [5]: result = s.query()

    In [6]: len(result)
    Out[6]: 1

通过使用这个模块获得相关的结果,这是非常容易的,但是您基本上只是在运行一个硬编码脚本,因此需要更改 OID 对象的值,以遍历系统子树:
清单 4. 更改 OID 对象的值


    In [7]: s.oid
    Out[7]: 'sysDescr'

    In [8]: s.oid = ".1.3.6.1.2.1.1"

    In [9]: result = s.query()

    In [10]: print result
    ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686', 
          '.1.3.6.1.4.1.8072.3.2.10', '121219', 'me@localhost.com', 
          'localhost', '"My Local 
    Machine"', '0', '.1.3.6.1.6.3.10.3.1.1', '.1.3.6.1.6.3.11.3.1.1', 
    '.1.3.6.1.6.3.15.2.1.1', 
    '.1.3.6.1.6.3.1', '.1.3.6.1.2.1.49', '.1.3.6.1.2.1.4', '.1.3.6.1.2.1.50',
     '.1.3.6.1.6.3.16.2.2.1', 
    'The SNMP Management Architecture MIB.', 'The MIB for Message Processing and
     Dispatching.', 'The management information definitions for the SNMP 
    User-based Security Model.', 'The MIB module for SNMPv2 entities', 'The 
    MIB module for managing TCP implementations', 'The MIB module for
    managing IP and ICMP implementations', 'The MIB module for managing 
    UDP implementations', 'View-based Access 
    Control Model for SNMP.', '0', '0', '0', '0', '0', '0', '0', '0')

正如您可以看到的,要使用这个模块并开始分析整个网络(一次一台计算机),这项任务是非常容易的。请仔细地进行分析,并确定需要在网络中进行查询的内容。这是 IPython 的另一个有趣的特性,有必要对其进行深入研究。IPython 具有一个令人难以置信的特性,即允许您将 Python 代码片段作为后台进程来运行。幸运的是,进行这项操作非常简单。让我们再次运行相同的查询,但这一次将其作为后台进程运行(请参见清单 5)。
清单 5. IPython 迭代式编码示例――后台进程


    In [11]: bg s.query()
    Starting job # 0 in a separate thread.

    In [12]: jobs[0].status
    Out[12]: 'Completed'

    In [16]: jobs[0].result
    Out[16]: 
    ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686',
     '.1.3.6.1.4.1.8072.3.2.10', '121219', 'me@localhost.com', 'localhost', '"My Local
     Machine"', '0', '.1.3.6.1.6.3.10.3.1.1', '.1.3.6.1.6.3.11.3.1.1', 
    '.1.3.6.1.6.3.15.2.1.1', '.1.3.6.1.6.3.1', '.1.3.6.1.2.1.49', 
    '.1.3.6.1.2.1.4', '.1.3.6.1.2.1.50', '.1.3.6.1.6.3.16.2.2.1',
     'The SNMP Management Architecture MIB.', 'The MIB for Message Processing and
     Dispatching.', 'The management information definitions for the SNMP User-based
     Security Model.', 'The MIB module for SNMPv2 entities', 'The MIB module for
     managing TCP implementations', 'The MIB module for managing IP and ICMP
     implementations', 'The MIB module for managing UDP implementations',
     'View-based Access Control Model for SNMP.', '0', '0', '0', '0', '0', '0', '0', '0')

令人激动的是,IPython 中的后台线程是一种非常有价值的功能,但它只能与支持异步线程的库一起工作。不幸的是,Net-SNMP 是同步的。如果您对这一点感兴趣,那么可以通过将 s.oid 值更改为 .iso 来进行测试。在查询完成之前,您应该可以注意到,IPython 解释器发生了"阻塞"或者"挂起"。尽管只是一个警告,但对整个 .iso 树的 SNMP 遍历可能会花费较长的时间,因此您可能会接受我的观点。

当然,还有另一种解决方案。您可以使用 Python 所提供的众多处理库中的其中一个,为这个阻塞的进程派生新的进程。Python Cheese Shop 提供了一些第三方库。如果您正在使用 easy_install,那么要安装一个包(如 Parallel Python)并使用 Net-SNMP 来测试这个库,将是相当简单的,因此这将由您来决定。


    easy_install http://www.parallelpython.com/downloads/pp/pp-1.5.zip

这里要展示的最后一个特性是,在 IPython Shell 中运行单元测试。在对模块进行更改时,需要频繁地运行单元测试,而这也是非常容易的。您需要添加一个标记以运行 run -e,这样一来,您就可以在 IPython Shell 中避免回溯到单元测试模块。您可以在本文所附带的源文件中下载这个单元测试。

请注意,IPython 0.8.2 还有一个新的文档测试特性,它允许您在 IPython 中生成文档测试。文档测试是 Python 的一个很好的特性,因为与其他特性一起,它提供了一种为 API 创建可测试文档的方法。下面给出了一个示例,以说明如何在 IPython 中为我们的模块运行 doctest:
清单 6.以 doctest 模式运行 IPython


    In [5]: %doctest_mode
    *** Pasting of code with ">>>" or "..." has been enabled.
    Exception reporting mode: Plain
    Doctest mode is: ON
    >>> from snmpinput import snmpSessionBaseClass

    >>> s = snmpSessionBaseClass()

    >>> s.query()
    ('Linux devmws2.racemi.com 2.6.9-55.0.2.EL #1 Tue Jun 26 14:08:18 EDT 2007 i686',)

因为 doctest 模式将不加分析地执行 Python 语句,所以您必须小心,不要在 doctest 中使用可能更改的值,就像上面所给出的值。如果您在模块的 docstring 中粘贴了数行代码,那么您可以通过使用下面的方法来测试您的 API 文档:


    def _test():
      import doctest
      doctest.testmod()

    if __name__ == "__main__":
      _test()

总结

在本文中,您已经了解了协同使用 Net-SNMP 和 IPython 将成为一种功能强大的组合。本文介绍了下面几个主要概念:

  • Python 绑定:Net-SNMP 现在提供了 Python 绑定,这使得我们能够充分地利用 Python 的功能来处理 SNMP 协议。
  • 处理库:目前,Python 绑定是同步的,但是使用处理库可以为每个请求派生新的进程,从而解决这个问题。
  • 灵活的技术:对于系统管理员和软件工程师来说,IPython 是一种非常成熟、并且功能非常强大的工具。尽管本文只是简要地介绍了几种灵活的技术,如文档测试和单元测试,但是您可以应用这些技术,以进行任何以测试为中心的开发、或者以交互的方式编写和分析代码。
  • SNMP 和 IPython:对于 SNMP 和 IPython 在单独或者共同使用时能够实现的功能,本文只是进行了简要介绍。

SNMP 非常复杂,它几乎使人们不敢想象编写任何有意义的代码,但是,我们希望本文所介绍的技术能够激发某些新的观点。如果您很好奇,想知道 SNMP 的 Python 实现究竟到了什么程度,那么可以研究一下 Zenoss,下载一个虚拟机,并对它进行测试。还有一个 API,您可以利用它来编写脚本,因此您可以将这里所学到的内容和全面的 Python NMS 相结合。当然,也适用于任何其他 NMS。

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录