检查表及总结 - 《代码大全》

本贴最后更新于 4045 天前,其中的信息可能已经时异事殊

为了更好的评估代码写的哪里有问题,我把《代码大全》里核心的部分 checklist 整理出来了,大家可以大概过一遍,不一定每写完一个程序都要一条一条的去检查,但心里应该有这么一张检查表,在写代码和 review 代码时自然而然的想起来。

设计

  • 设计是否经过多次迭代,并最终决定了最好的一个?
  • 是否同时使用自上而下和自下而上的方法来解决设计问题?
  • 类与类之间的交互关系是否已经设计为最小化?
  • 设计被划分为层次吗?
  • 你对把这一程序分解成为子程序,包和类的方式感到满意吗?
  • 程序是不是易于维护?
  • 设计是否精简?设计出来的每一个部分都绝对必要吗?
  • 整体而言,你的设计是否有助于最小化偶然性和本质性的复杂度吗?

类的设计

  • 你是否把程序中的类都看做是抽象数据类型了?是否从这个角度评估它们的接口了?
  • 类是否有一个中心目的?
  • 类的命名是否恰当?其名字是否表达了其中新目的?
  • 类的接口是否展现了一致的抽象?
  • 类的接口是否能让人清楚明白的知道如何用它?
  • 类的接口是否抽象,使你能不必顾虑他是如何实现其服务的?你能把类看做黑盒子吗?
  • 类提供的服务是否足够完整,让其它类无需动用其内部数据?
  • 是否已从类中去除无关信息?
  • 是否考虑过把类进一步分解?
  • 在修改类时是否维持了其接口的完整性?
  • 是否把成员的可访问性降到最小?
  • 是否避免暴露类的数据成员?
  • 类是否避免对其使用者,包括其派生类会如何使用它做了假设?
  • 类是否不依赖于其它类?它是松散耦合吗?
  • 继承是否只用来建立一个 is a 关系?派生类是否遵循了 LSP 原则。
  • 继承层次是否很浅?
  • 类中是否只有大约七个或者更少的成员?
  • 是否把类直接或者间接调用其他类的子程序的数量减到最少?
  • 类是否在绝对必要时才与其他类写作?
  • 是否在构造函数中初始化了所有的数据成员?

子程序

  • 创建子程序的理由充分吗?
  • 一个子程序中所有适合单独提出的部分是不是已经被提出到单独的子程序中了?
  • 过程的名字是否用了强烈、清晰的动词加宾语的词组,函数的名字是否描述了其返回值?
  • 子程序的名字是否描述它所作的全部事情?
  • 子程序是否具有强烈的功能上的内聚性?
  • 子程序之间是否有较松散的耦合?子程序与其它子程序之间的连接是否是最小的,明确的,可见的,灵活的?
  • 子程序的长度是否是由其功能和逻辑自然确定,而非遵循任何人为的编码标准?
  • 子程序的参数表是否表现出一种具有整体性且一致的抽象?
  • 子程序参数的排列顺序是否合理?是否与类似的子程序的参数排列相符?
  • 接口假定是否在文档中说明?
  • 子程序的参数是否没有超过 7 个?
  • 是否用到了每一个输入参数,是否用到了每一个输出参数?
  • 子程序是否避免了把输入参数用作工作变量?
  • 如果子程序是一个函数,那么它是否在所有可能的情况下都能返回一个合法的值?

防御式编程

  • 子程序是否保护自己免遭有害输入数据的破坏?
  • 你用断言来说明编程假定吗?其中包括了前条件和后条件了吗?
  • 断言是否只说明从来不应该发生的情况?
  • 你是否在架构或者高层设计中规定了一组特定的错误处理技术?
  • 你是否在架构或者高层设计中规定了是让错误处理更倾向于健壮性还是正确性?
  • 代码中用到辅助调试的代码了吗?
  • 在防御式编程时引入的代码量是否适宜,既不过多也不过少?
  • 你在项目中定义了一套标准化的异常处理方案吗?
  • 如果可能的话,是否在局部处理了错误而不是把它当成一个异常跑出去?
  • 所有异常是否都与抛出他们的子程序在同一抽象层次上?
  • 每个异常是否包含了关于异常发生的所有背景信息?
  • 代码中是否没有空的 catch 语句?
  • 检查有害输入数据的代码是否也检查了故意的缓冲区溢出,SQL 注入,HTML 注入,整数溢出及其他恶意输入数据?
  • 是否检查了所有的错误返回码?
  • 是否捕获了所有的异常?
  • 出错消息中是否避免出现有助于攻击者攻入系统所需的信息?

伪代码

  • 是否检查过已满足所有的先决条件?
  • 定义好这个类要解决的问题了吗?
  • 高层次的设计是否清晰?能给这个类和其中的每个子程序起一个好的名字吗?
  • 考虑过该如何测试这个类及其中的每个子程序吗?
  • 关于效率的问题,你主要从稳定的接口和可读的实现这两个角度考虑吗?还是主要从满足资源和速度的预期目标的角度考虑过呢?
  • 从标准库函数和其它代码库中寻找过可用的子程序或者组件吗?
  • 从参考书中查过有用的算法了吗?
  • 是否用详尽的伪代码设计好每一个子程序?
  • 你在脑海里检查过伪代码吗?这些伪代码容易理解吗?
  • 关注过那些可能让你重返设计的警告信息了吗?
  • 是否把伪代码正确的翻译成代码了?
  • 你反复使用伪代码编程过程了吗?
  • 在做出假定的时候有没有对它们加以说明?
  • 已经删除了那些冗余的注释了吗?
  • 你是否采取了几次迭代中最好的那个结果?还是在第一次迭代之后就停止了?
  • 你完全理解你的代码了吗?这些代码是否容易理解?

变量

  • 变量声明位置靠近变量第一次使用的位置吗?
  • 尽可能在变量声明的同时初始化变量吗?
  • 计数器和累加器经过适当初始化了吗?如果需要再一次使用,之前重新初始化了吗?
  • 适当的重新初始化“需要重复执行的代码里的变量”了吗?
  • 代码在通过编译器编译的时候是不是没有警告信息?你启用了所有可用的警告信息了吗?
  • 如果语言允许隐式声明,你为由此可能引发的问题做好补偿措施了吗?
  • 如果可能,所有变量都被定义为具有最小的作用域吗?
  • 各变量的引用点都尽可能集中在一起吗?对同一个变量的两次相邻引用,或者变量的整个生命期都这样做了吗?
  • 控制结构符合数据类型吗?
  • 所有声明的变量都用了吗?
  • 变量都在合适的时间绑定了吗?也就是说你有意识的在晚期绑定所带来的灵活性和增加复杂度之间做出平衡了吗?
  • 每个变量都有且仅有一项用途吗?
  • 每个变量的含义都很明确且没有隐含含义吗?

变量命名

  • 名字完整并且准确的表达了变量所代表的含义吗?
  • 名字足够长,可以让你无需苦苦思索吗?
  • 如果有计算限定符,它被放在名字后面吗?
  • 名字中用 Count 或者 index 来掉提 Num 了吗?
  • 循环小标的名字有意义吗?
  • 所有临时的变量都重新命名为更有意义的名字了吗?
  • 当布尔变量为真时,变量能准确表达其含义吗?
  • 枚举中的名字含有能够表示其类别的前缀或者后缀吗?
  • 具名常量是根据它所代表的抽象实体儿不是它所代表的数字来命名的吗?
  • 命名规则能够区分局部数据,类的数据和全局数据吗?
  • 规则能够区分类型名,具名常量,枚举类型和变量名吗?
  • 规则能够在编译器不强制检测只读参数的语言里表示出子程序的输入参数吗?
  • 规则能尽可能地与语言的标准规则兼容吗?
  • 名字为可读性而加以格式化了吗?
  • 是否避免只为了省一个字符而缩写的情况?
  • 所有单词的缩写方式都一致吗?
  • 名字能够读出来吗?
  • 避免使用容易被看错和读错的名字吗?
  • 在缩写对照表里对端名字做出说明了吗?

基本数据类型

  • 代码中避免使用神秘数值了吗?
  • 代码考虑了除零错误了吗?
  • 类型转换很明显吗?
  • 如果一条语句中存在两个不同类型的变量,那么这条语句会像你期望的那样求值吗?
  • 代码避免了混合类型比较吗?
  • 使用整数除法表达式能按预期的那样工作吗?
  • 整数表达式避免整数溢出问题了吗?
  • 代码避免了对数量级相差具体大浮点数做加减运算了吗?
  • 代码系统地阻止了舍入错误的发生吗?
  • 代码避免对浮点数值做等量比较了吗?
  • 代码避免使用神秘字符和字符串了吗?
  • 使用字符串时避免了 off-bye-one 错误了吗?
  • 程序用额外的布尔变量来说明条件判断了吗?
  • 程序用额外的布尔变量来简化条件判断了吗?
  • 程序用枚举类型而非具名常量来提高可读性和可修改行了吗?
  • 当变量不能用 true 和 false 表示的时候,程序用枚举类型来取代布尔变量了吗?
  • 针对枚举类型的才测试检测了非法数值了吗?
  • 把枚举类型的第一项条目保留为“非法的”了吗?
  • 具名常量使用一致吗?没有在某些位置使用具名常量又在其他位置使用文字量?
  • 所有的数组下标都没有超出数组边界吗?
  • 数组引用没有出现 off-by-one 的错误吗?
  • 所有的多维数组的下标顺序都正确吗?
  • 在嵌套循环里,把正确的变量用于数组下标来避免下标错乱吗?

不常见的数据类型

  • 你使用结构体而不是使用单纯的变量来组织和操作相关的数据吗?
  • 你考虑过创建一个类来代替使用结构体吗?
  • 所有的变量是否都是局部或者是类范围的?除非绝对有必要才是全局的?
  • 你对所有的全局变量都加以文档说明吗?
  • 避免使用伪全局数据,即被四处传递且含有杂乱数据的的巨大对象吗?
  • 用访问器子程序来取代全局数据了吗?
  • 把访问其子程序和数据组织到类里了吗?
  • 访问器子程序提供了一个在底层数据类型实现之上的抽象层吗?
  • 所有相关的访问器子程序都位于同一抽象层吗?
  • 把指针操作隔离在子程序里了吗?
  • 指针引用合法吗?或者指针有可能成为悬空指针吗?
  • 代码在使用指针之前检查它的有效性了吗?
  • 在使用指针所指向的变量之前检查其有效性了吗?
  • 指针用完后被设置为空了吗?
  • 就可读性而言,代码用了所有需要使用的指针变量了吗?
  • 链表中的指针是按正确的顺序加以释放的吗?
  • 程序分配了一片保留的内存后备区域,以便在耗尽内存的时候能够优雅地退出吗?
  • 是不是在没有其他方法可用的情况下最终才使用指针的?

组织直线型代码

  • 代码使得语句之间的依赖关系变得明显吗?
  • 子程序的名字使得依赖关系变得明显吗?
  • 子程序的参数使得依赖关系变得明显吗?
  • 如果依赖关系不明确,你是否用注释进行了说明?
  • 你用“内务管理变量”来检查代码中关键位置的顺序依赖关系了吗?
  • 代码容易按照自上而下的顺序阅读吗?
  • 相关的语句组织在一起吗?
  • 把相对独立的语句组放进各自的子程序里吗?

使用条件语句

  • 代码的正常路径清晰吗?
  • if-then 测试对等量分支的处理方式正确吗?
  • 使用了 else 字句并加以说明了吗?
  • else 字句用的对吗?
  • 用对了 if 和 else 字句,即没有把它们用反吗?
  • 需要执行的正常情况维护 if 而不是 else 字句里吗?
  • if-then-else-if 把复杂的判断封装到布尔函数里了吗?
  • if-then-else-if 先判断最常见的情况了吗?
  • if-then-else-if 判断包含所有的情况吗?
  • if-then-else-if 是最佳的实现吗?比 Case 语句还要好吗?
  • case 子句排序的有意义吗?
  • case 子句的每种情况操作简单吗?必要的时候调用了其它子程序了吗?
  • case 语句检测的是一个真实的变量,而不是为了滥用 case 语句而而刻意制造变量吗?
  • 默认字句用的合法吗?
  • 用默认字句来检测和报告意料之外的情况了吗?
  • 在 c,c++ 和 java 里,每一个 case 的末尾有一个 break 吗?

循环

  • 在合适的情况下用 while 循环取代 for 循环了吗?
  • 循环是由内到外创建的吗?
  • 是从循环的头部进入循环的吗?
  • 初始化代码是直接位于循环前面吗?
  • 循环是无限循环或者事件循环吗?阿德结构是否清晰?
  • 避免使用像 for i = 1 to 9999 这样的代码吗?
  • 如果这是一个 c++,c 或 java 中的 for 循环,那么把循环头留给循环控制代码了吗?
  • 循环使用了{}及其等价物来括上循环体,以防止因修改不当而出错吗?
  • 循环体内有内容吗?他是非空的吗?
  • 把内务处理集中地放在循环开始或者循环结束处了吗?
  • 循环像定义良好的子程序那样只执行一件操作吗?
  • 循环短的足以一目了然吗?
  • 循环的嵌套层次不多于 3 层吗?
  • 把长循环的内容提取成单独的子程序吗?
  • 如果循环很长,那么它非常清晰吗?
  • 如果这是一个 for 循环,那么其中的代码有没有随意修改循环下标值?
  • 是否把重要的循环下标值保存在另外的变量里,而不是在循环体外使用该循环下标?
  • 循环下标是序数类型或者枚举类型,而不是浮点类型吗?
  • 循环下标的名字有意义吗?
  • 循环避免了下标串话问题吗?
  • 循环是在所有可能的条件下都能终止吗?
  • 如果建立了某种安全计数器标准,循环使用了安全计数器了吗?
  • 循环的退出条件清晰吗?
  • 如果使用了 break 或者 continue,那么它们用对了吗?
  • 不常见的控制结构
  • 每一个子程序都仅在有必要的时候才使用 return 吗?
  • 使用 return 有助于增强可读性吗?
  • 递归子程序中包含了停止递归的代码吗?
  • 子程序用安全计数器来确保子程序能停下来吗?
  • 递归只位于一个子程序里面吗?
  • 子程序递归深度处于程序栈容量可以满足的限度内吗?
  • 递归是实现子程序的最佳方法吗?它要好于简单的迭代吗?
  • 是否在万不得已的时候才使用 goto?如果用了 goto,是否仅仅处于增强可读性和可维护性呢?
  • 如果处于效率因素而使用的 goto,那么对这种效率上的提升做出衡量并且加以说明了吗?
  • 一个子程序里最多只用了一个 goto 标号吗?
  • 所有的 goto 都向前跳转,而不是向后跳转吗?
  • 所有的 goto 标号都用到了吗?

表驱动法

  • 你考虑过把表驱动法作为复杂逻辑的替代方案吗?
  • 你考虑过把表驱动法作为复杂继承结构的替代方案吗?
  • 你考虑过把表数据存储在外部并在运行期间读入,以便在不修改代码的情况下就可以改变这些数据吗?
  • 如果无法用一种简单的数组索引去访问表,那么你把机酸访问键值的功能提取成单独的子程序,而不是在代码中重复地计算键值吗?

一般控制问题

  • 表达式中用的是 true 和 false,而不是 1 和 0 吗?
  • 布尔值和 true 以及 false 做比较是隐式进行的吗?
  • 对数值做比较是显式进行的吗?
  • 有没有通过增加新的布尔变量,使用布尔函数和决策表来简化表达式?
  • 布尔表达式是用肯定形式表达的吗?
  • 括号配对吗?
  • 在需要括号来明确的地方都使用括号了吗
  • 判断是按照数轴顺序编写了吗?
  • 如果适当的话,java 中的判断用的是 a.equals(b)方式,而没有用 a==b 方式吗?
  • 空语句表述得明显吗?
  • 用重新判断部分条件,转换成 if-then-else 或者 case 语句、把嵌套代码提取成单独的子程序、换成一种更面向对象的设计或者其他的改进方法来简化嵌套语句了吗?
  • 如果一个子程序的决策点超过 10 个,那么能提出不重新设计的理由吗?

转自:http://www.cnblogs.com/onlytiancai/archive/2010/05/30/1747556.html

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    132 引用 • 189 回帖
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1114 回帖 • 124 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 175 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 3 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 9 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 733 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 210 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    105 引用 • 127 回帖 • 382 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 642 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖 • 1 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 531 关注
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 611 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 724 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 232 回帖 • 2 关注
  • gRpc
    11 引用 • 9 回帖 • 73 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 43 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 529 关注
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    41 引用 • 130 回帖 • 261 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 9 关注
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    311 引用 • 546 回帖