`
coolerbaosi
  • 浏览: 721922 次
文章分类
社区版块
存档分类
最新评论

使用 Lua 编写可嵌入式脚本

 
阅读更多
虽然编译性编程语言和脚本语言各自具有自己独特的优点,但是如果我们使用这两种类型的语言来编写大型的应用程序会是什么样子呢?Lua 是一种嵌入式脚本语言,它非常小,速度很快,功能却非常强大。在创建其他配置文件或资源格式(以及与之对应的解析器)之前,请尝试一下 Lua。

尽管诸如 Perl、Python、PHP 和 Ruby 之类的解释性编程语言日益被 Web 应用程序广泛地采纳 —— 它们已经长期用来实现自动化系统管理任务 —— 但是诸如 C、C++ 之类的编译性编程语言依然是必需的。编译性编程语言的性能是脚本语言所无法企及的(只有手工调优的汇编程序的性能才能超过它),有些软件 —— 包括操作系统和设备驱动程序 —— 只能使用编译代码来高效地实现。实际上,当软件和硬件需要进行无缝地连接操作时,程序员本能地就会选择 C 编译器:C 非常基础,距离 “原始金属材料非常近” —— 即可以操作硬件的很多特性 —— 并且 C 的表现力非常强大,可以提供高级编程结构,例如结构、循环、命名变量和作用域。

然而,脚本语言也有自己独特的优点。例如,当某种语言的解释器被成功移植到一种平台上以后,使用这种语言编写的大量脚本就可以不加任何修改在这种新平台上运行 —— 它们没有诸如系统特定的函数库之类的依赖限制。(我们可以考虑一下 Microsoft® Windows® 操作系统上的许多 DLL 文件和 UNIX® 及 Linux® 上的很多 libcs)。另外,脚本语言通常都还会提供高级编程构造和便利的操作,程序员可以使用这些功能来提高生产效率和灵活性。另外,使用解释语言来编程的程序员工作的速度更快,因为这不需要编译和链接的步骤。C 及其类似语言中的 “编码、编译、链接、运行” 周期缩减成了更为紧凑的 “编写脚本、运行”。

Lua 新特性

与其他脚本语言一样,Lua 也有自己的一些特性:

  • Lua 类型。在 Lua 中,值可以有类型,但是变量的类型都是动态决定的。nil、布尔型、数字 和 字符串 类型的工作方式与我们期望的一样。
    • Nil 是值为nil的一种特殊类型,用来表示没有值。
    • 布尔型的值可以是truefalse常量。(Nil也可以表示 false,任何非nil的值都表示 true。)
    • Lua 中所有的数字都是双精度的(不过我们可以非常简便地编写一些代码来实现其他数字类型)。
    • 字符串是定长字符数组。(因此,要在一个字符串后面附加上字符,必须对其进行拷贝。)
  • 表、函数 和线程 类型都是引用。每个都可以赋值给一个变量,作为参数传递,或作为返回值从函数中返回。例如,下面是一个存储函数的例子:

    -- example of an anonymous function
    -- returned as a value
    -- see http://www.tecgraf.puc-rio.br/~lhf/ftp/doc/hopl.pdf
    function add(x)
      return function (y) return (x + y) end
    end
    f = add(2)
    print(type(f), f(10))
    function  12
  • Lua 线程。线程是通过调用内嵌函数coroutine.create(f)创建的一个协同例程 (co-routine),其中 f 是一个 Lua 函数。线程不会在创建时启动;相反,它是在创建之后使用coroutine.resume(t)启动的,其中 t 就是一个线程。每个协同例程都必须使用coroutine.yield()偶尔获得其他协同例程的处理器。
  • 赋值语句。Lua 允许使用多种赋值语句,可以先对表达式进行求值,然后再进行赋值。例如,下面的语句:

    i = 3
    a = {1, 3, 5, 7, 9}
    i, a[i], a[i+1], b = i+1, a[i+1], a[i]
    print (i, a[3], a[4], b, I)

    会生成4 7 5 nil nil。如果变量列表的个数大于值列表的个数,那么多出的变量都被赋值为nil;因此,b就是 nil。如果值的个数多于变量的个数,那么多出的值部分就会简单地丢弃。在 Lua 中,变量名是大小写敏感的,这可以解释为什么I的值是 nil。
  • 块(Chunk)。块 可以是任何 Lua 语句序列。块可以保存到文件中,或者保存到 Lua 程序中的字符串中。每个块都是作为一个匿名函数体来执行的。因此,块可以定义局部变量和返回值。
  • 更酷的东西。Lua 具有一个标记-清理垃圾收集器。在 Lua 5.1 中,垃圾收集器是以增量方式工作的。Lua 具有完整的词法闭包(这与 Scheme 类似,而与 Python 不同)。Lua 具有可靠的尾部调用语义(同样,这也与 Scheme 类似,而与 Python 不同)。

在 Programming in Lua 和 Lua-users wiki (链接请参见后面的参考资料部分)中可以找到更多 Lua 代码的例子。

在所有的工程任务中,要在编译性语言和解释性语言之间作出选择,就意味着要在这种环境中对每种语言的优缺点、权重和折中进行评测,并接受所带来的风险。

在两个世界之间最好地进行混合

如果您希望充分利用这两个世界的优点,应该怎样办呢,是选择最好的性能还是选择高级强大的抽象?更进一步说,如果我们希望对处理器密集且依赖于系统的算法和函数以及与系统无关且很容易根据需要而进行修改的单独逻辑进行优化,那又当如何呢?

对高性能代码和高级编程的需要进行平衡是 Lua(一种可嵌入式脚本语言)要解决的问题。在需要时我们可以使用编译后的代码来实现底层的功能,然后调用 Lua 脚本来操作复杂的数据。由于 Lua 脚本是与编译代码独立的,因此我们可以单独修改这些脚本。使用 Lua,开发周期就非常类似于 “编码、编译、运行、编写脚本、编写脚本、编写脚本 ...”。

例如,Lua Web 站点 “使用” 页面(请参见参考资料)列出了主流市场上的几个计算机游戏,包括 World of Warcraft 和(家用版的)Defender,它们集成 Lua 来实现很多东西,从用户界面到敌人的人工智能都可以。Lua 的其他应用程序包括流行的 Linux 软件更新工具 apt-rpm 的扩展机制,还有 “Crazy Ivan” Robocup 2000 冠军联赛的控制逻辑。这个页面上的很多推荐感言都对 Lua 的小巧与杰出性能赞不绝口。

开始使用 Lua

Lua 5.0.2 版本是撰写本文时的最新版本,不过最近刚刚发布了 5.1 版本。您可以从 lua.org 上下载 Lua 的源代码,在 Lua-users wiki(链接请参见参考资料)上可以找到预先编译好的二进制文件。完整的 Lua 5.0.2 核心文件中包括了标准库和 Lua 编译器,不过只有 200KB 大小。

如果您使用的是 Debian Linux,那么可以以超级用户的身份运行下面的命令来快速安装 Lua 5.0:

# apt-get install lua50

本文中给出的例子都是在 Debian Linux Sarge 上运行的,使用的是 Lua 5.0.2 和 2.4.27-2-686 版本的 Linux 内核。

在系统上安装好 Lua 之后,我们可以首先来试用一下单独的 Lua 解释器。(所有的 Lua 应用程序必须要嵌入到宿主应用程序中。解释器只是一种特殊类型的宿主,对于开发和调试工作来说非常有用。)创建一个名为 factorial.lua 的文件,然后输入下面的代码:

-- defines a factorial function
function fact (n)
  if n == 0 then
    return 1
  else
    return n * fact(n-1)
  end
end

print("enter a number:")
a = io.read("*number")
print(fact(a))

factorial.lua 中的代码 —— 更确切地说是任何 Lua 语句序列 —— 都称为一个块,这在上面的Lua 特性中已经进行了介绍。要执行刚才创建的代码块,请运行命令lua factorial.lua

$ lua factorial.lua
enter a number:
10
3628800

或者像在其他解释性语言中一样,我们可以在代码顶部添加一行 “标识符”(#!),使这个脚本变成可执行的,然后像单独命令一样来运行这个文件:

$ (echo '#! /usr/bin/lua'; cat factorial.lua) > factorial 
$ chmod u+x factorial
$ ./factorial
enter a number:
4
24

Lua 语言

Lua 具有现代脚本语言中的很多便利:作用域,控制结构,迭代器,以及一组用来处理字符串、产生及收集数据和执行数学计算操作的标准库。在 Lua 5.0 Reference Manual 中有对 Lua 语言的完整介绍(请参见参考资料)。

在 Lua 中,只有值 具有类型,而变量的类型是动态决定的。Lua 中的基本类型(值)有 8 种: nil,布尔型,数字,字符串,函数,线程,表 以及 用户数据。前 6 种类型基本上是自描述的(例外情况请参见上面的Lua 特性一节);最后两个需要一点解释。

Lua 表

在 Lua 中,表是用来保存所有数据的结构。实际上,表是 Lua 中惟一的 数据结构。我们可以将表作为数组、字典(也称为散列 或联合数组)、树、记录,等等。

与其他编程语言不同,Lua 表的概念不需要是异构的:表可以包含任何类型的组合,也可以包含类数组元素和类字典元素的混合体。另外,任何 Lua 值 —— 包括函数或其他表 —— 都可以用作字典元素的键值。

要对表进行浏览,请启动 Lua 解释器,并输入清单 1 中的黑体显示的代码。


清单 1. 体验 Lua 表

$ lua
> -- create an empty table and add some elements
> t1 = {}
> t1[1] = "moustache"
> t1[2] = 3
> t1["brothers"] = true

> -- more commonly, create the table and define elements
> all at once
> t2 = {[1] = "groucho", [3] = "chico", [5] = "harpo"}
> t3 = {[t1[1]] = t2[1], accent = t2[3], horn = t2[5]}
> t4 = {}
> t4[t3] = "the marx brothers"
> t5 = {characters = t2, marks = t3}
> t6 = {["a night at the opera"] = "classic"}

> -- make a reference and a string
> i = t3
> s = "a night at the opera"

> -- indices can be any Lua value
> print(t1[1], t4[t3], t6[s])
moustache   the marx brothers classic

> -- the phrase table.string is the same as table["string"]
> print(t3.horn, t3["horn"])
harpo   harpo

> -- indices can also be "multi-dimensional"
> print (t5["marks"]["horn"], t5.marks.horn)
harpo   harpo

> -- i points to the same table as t3
> = t4[i]
the marx brothers

> -- non-existent indices return nil values
> print(t1[2], t2[2], t5.films)
nil     nil     nil

>  -- even a function can be a key 
> t = {}
> function t.add(i,j)
>> return(i+j)
>> end
> print(t.add(1,2))
3
> print(t['add'](1,2))
3
>  -- and another variation of a function as a key 
> t = {}
> function v(x)
>> print(x)
>> end
> t[v] = "The Big Store"
> for key,value in t do key(value) end
The Big Store

正如我们可能期望的一样,Lua 还提供了很多迭代器函数来对表进行处理。全局变量table提供了这些函数(是的,Lua 包就是表)。有些函数,例如table.foreachi(),会期望一个从 1(数字 1)开始的连续整数范围:

> table.foreachi(t1, print)
1 moustache
2 3

另外一些函数,例如table.foreach(),会对整个表进行迭代:

> table.foreach(t2,print)
1       groucho
3       chico
5       harpo
> table.foreach(t1,print)
1       moustache
2       3
brothers        true

尽管有些迭代器对整数索引进行了优化,但是所有迭代器都只简单地处理 (key, value) 对。

现在我们可以创建一个表t,其元素是{2, 4, 6, language="Lua", version="5", 8, 10, 12, web="www.lua.org"},然后运行table.foreach(t, print)table.foreachi(t, print)

用户数据

由于 Lua 是为了嵌入到使用另外一种语言(例如 C 或 C++)编写的宿主应用程序中,并与宿主应用程序协同工作,因此数据可以在 C 环境和 Lua 之间进行共享。正如 Lua 5.0 Reference Manual 所说,userdata类型允许我们在 Lua 变量中保存任意的 C 数据。我们可以认为userdata就是一个字节数组 —— 字节可以表示指针、结构或宿主应用程序中的文件。

用户数据的内容源自于 C,因此在 Lua 中不能对其进行修改。当然,由于用户数据源自于 C,因此在 Lua 中也没有对用户数据预定义操作。不过我们可以使用另外一种 Lua 机制来创建对userdata进行处理的操作,这种机制称为 元表(metatable)。

元表

由于表和用户数据都非常灵活,因此 Lua 允许我们重载这两种类型的数据的操作(不能重载其他 6 种类型)。元表 是一个(普通的)Lua 表,它将标准操作映射成我们提供的函数。元表的键值称为事件;值(换而言之就是函数)称为元方法。

函数setmetatable()getmetatable()分别对对象的元表进行修改和查询。每个表和userdada对象都可以具有自己的元表。

例如,添加操作对应的事件是__add。我们可以推断这段代码所做的事情么?

-- Overload the add operation
-- to do string concatenation
--
mt = {}

function String(string)
  return setmetatable({value = string or ''}, mt)
end

-- The first operand is a String table
-- The second operand is a string
-- .. is the Lua concatenate operator
--
function mt.__add(a, b)
  return String(a.value..b)
end

s = String('Hello')
print((s + ' There ' + ' World!').value )

这段代码会产生下面的文本:

Hello There World!

函数String()接收一个字符串string,将其封装到一个表({value = s or ''})中,并将元表mt赋值给这个表。函数mt.__add()是一个元方法,它将字符串b添加到在a.value中找到的字符串后面b次。这行代码print((s + ' There ' + ' World!').value )调用这个元方法两次。

__index是另外一个事件。__index的元方法每当表中不存在键值时就会被调用。下面是一个例子,它记住 (memoize) 函数的值:

-- code courtesy of Rici Lake, rici@ricilake.net
function Memoize(func, t)
  return setmetatable(
     t or {},
    {__index =
      function(t, k)
        local v = func(k);
        t[k] = v;
        return v;
        end
    }
  )
end

COLORS = {"red", "blue", "green", "yellow", "black"}
color = Memoize(
  function(node)
    return COLORS[math.random(1, table.getn(COLORS))]
    end
)

将这段代码放到 Lua 解释器中,然后输入print(color[1], color[2], color[1])。您将会看到类似于blue black blue的内容。

这段代码接收一个键值node,查找 node 指定的颜色。如果这种颜色不存在,代码就会给node赋一个新的随机选择的颜色。否则,就返回赋给 node 的颜色。在前一种情况中,__index元方法被执行一次以分配一个颜色。后一种情况比较简单,所执行的是快速散列查找。

Lua 语言提供了很多其他功能强大的特性,所有这些特性都有很好的文档进行介绍。在碰到问题或希望与专家进行交谈时,请连接 Lua Users Chat Room IRC Channel(请参见参考资料)获得非常热心的支持。

嵌入和扩展

除了语法简单并且具有功能强大的表结构之外,Lua 的强大功能使其可以与宿主语言混合使用。由于 Lua 与宿主语言的关系非常密切,因此 Lua 脚本可以对宿主语言的功能进行扩充。但是这种融合是双赢的:宿主语言同时也可以对 Lua 进行扩充。举例来说,C 函数可以调用 Lua 函数,反之亦然。

Lua 与宿主语言之间的这种共生关系的核心是宿主语言是一个虚拟堆栈。虚拟堆栈与实际堆栈类似,是一种后进先出(LIFO)的数据结构,可以用来临时存储函数参数和函数结果。要从 Lua 中调用宿主语言的函数(反之亦然),调用者会将一些值压入堆栈中,并调用目标函数;被调用的函数会弹出这些参数(当然要对类型和每个参数的值进行验证),对数据进行处理,然后将结果放入堆栈中。当控制返回给调用程序时,调用程序就可以从堆栈中提取出返回值。

实际上在 Lua 中使用的所有的 C 应用程序编程接口(API)都是通过堆栈来进行操作的。堆栈可以保存 Lua 的值,不过值的类型必须是调用程序和被调用者都知道的,特别是向堆栈中压入的值和从堆栈中弹出的值更是如此(例如lua_pushnil()lua_pushnumber()

清单 2 给出了一个简单的 C 程序(节选自参考资料中 Programming in Lua 一书的第 24 章),它实现了一个很小但却功能完善的 Lua 解释器。


清单 2. 一个简单的 Lua 解释器

1 #include <stdio.h>
 2 #include <lua.h>
 3 #include <lauxlib.h>
 4 #include <lualib.h>
 5
 6 int main (void) {
 7   char buff[256];
 8   int error;
 9   lua_State *L = lua_open();   /* opens Lua */
10   luaopen_base(L);             /* opens the basic library */
11   luaopen_table(L);            /* opens the table library */
12   luaopen_io(L);               /* opens the I/O library */
13   luaopen_string(L);           /* opens the string lib. */
14   luaopen_math(L);             /* opens the math lib. */
15
16   while (fgets(buff, sizeof(buff), stdin) != NULL) {
17     error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
18             lua_pcall(L, 0, 0, 0);
19     if (error) {
20       fprintf(stderr, "%s", lua_tostring(L, -1));
21       lua_pop(L, 1);  /* pop error message from the stack */
22     }
23   }
24
25   lua_close(L);
26   return 0;
27 }

第 2 行到第 4 行包括了 Lua 的标准函数,几个在所有 Lua 库中都会使用的方便函数以及用来打开库的函数。第 9 行创建了一个 Lua 状态。所有的状态最初都是空的;我们可以使用luaopen_...()将函数库添加到状态中,如第 10 行到第 14 行所示。

第 17 行和luaL_loadbuffer()会从stdin中以块的形式接收输入,并对其进行编译,然后将其放入虚拟堆栈中。第 18 行从堆栈中弹出数据并执行之。如果在执行时出现了错误,就向堆栈中压入一个 Lua 字符串。第 20 行访问栈顶(栈顶的索引为-1)作为 Lua 字符串,打印消息,然后从堆栈中删除该值。

使用 C API,我们的应用程序也可以进入 Lua 状态来提取信息。下面的代码片段从 Lua 状态中提取两个全局变量:

..
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
  error(L, "cannot run configuration file: %s", lua_tostring(L, -1));

lua_getglobal(L, "width");
lua_getglobal(L, "height");
..
width = (int) lua_tonumber(L, -2);
height = (int) lua_tonumber(L, -1);
..

请再次注意传输是通过堆栈进行的。从 C 中调用任何 Lua 函数与这段代码类似:使用lua_getglobal()来获得函数,将参数压入堆栈,调用lua_pcall(),然后处理结果。如果 Lua 函数返回 n 个值,那么第一个值的位置在堆栈的 -n 处,最后一个值在堆栈中的位置是 -1。

反之,在 Lua 中调用 C 函数也与之类似。如果您的操作系统支持动态加载,那么 Lua 可以根据需要来动态加载并调用函数。(在必须使用静态加载的操作系统中,可以对 Lua 引擎进行扩充,此时调用 C 函数时需要重新编译 Lua。)

结束语

Lua 是一种学习起来容易得难以置信的语言,但是它简单的语法却掩饰不了其强大的功能:这种语言支持对象(这与 Perl 类似),元表使表类型具有相当程度的可伸展性,C API 允许我们在脚本和宿主语言之间进行更好的集成和扩充。Lua 可以在 C、C++、C#、Java™ 和 Python 语言中使用。

在创建另外一个配置文件或资源格式(以及相应的处理程序)之前,请尝试一下 Lua。Lua 语言及其社区非常健壮,具有创新精神,随时准备好提供帮助。

分享到:
评论

相关推荐

    asp代码ASP家教信息管理系统(源代码+论文)

    asp代码ASP家教信息管理系统(源代码+论文)本资源系百度网盘分享地址

    基于ssm高校毕业选题管理系统.zip

    基于ssm高校毕业选题管理系统.zip

    基于旷视研究院领先的深度学习算法,提供满足多业务场景的预训练模型.zip

    人工智能毕业设计&课程设计

    tensorflow_model_optimization-0.1.3.dev0-py2.py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    tensorflow_model_analysis-0.15.0-py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    粒子群算法.docx 粒子群算法(Particle Swarm Optimization,PSO)是一种优化算法,受到鸟群或鱼

    粒子群算法 粒子群算法(Particle Swarm Optimization,PSO)是一种优化算法,受到鸟群或鱼群等群体行为的启发。该算法通过模拟群体中个体之间的合作和竞争来搜索最优解。粒子群算法通常用于解决连续优化问题。 ### 工作原理: 1. **初始化**:随机生成一群粒子(也称为个体),每个粒子代表搜索空间中的一个解,并随机初始化其位置和速度。 2. **评估**:根据每个粒子的位置,计算其对应的适应度值(目标函数值)。 3. **更新**:根据个体最优和全局最优的情况,更新每个粒子的速度和位置。粒子会根据自己历史最好的位置以及整个群体历史最好的位置进行调整,以期望更好的搜索方向。 4. **迭代**:重复评估和更新步骤,直到满足停止条件(如达到最大迭代次数、目标函数值足够接近最优解等)。 ### 主要参数: - 粒子数量(Population Size):群体中粒子的数量,通常越大越容易找到全局最优解,但计算成本也会增加。 - 惯性权重(Inertia Weight):控制粒子运动的惯性,平衡局部搜索和全局搜索能力。通常随着迭代次数增加而逐渐减小。

    20210327 AI-for-Drug-Discovery-2020.pdf

    20210327 AI-for-Drug-Discovery-2020

    tensorflow_model_optimization-0.1.2-py2.py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    Linux创建虚拟机的步骤

    Linux创建虚拟机的步骤

    基于SpringBoot的校园二手书交易管理系统设计源码

    这是一个基于SpringBoot开发的校园二手书交易管理系统,使用Java语言,包含102个文件。主要文件类型包括39个Java源文件、23个HTML文件、10个PNG图片文件、9个XML文件、9个JavaScript文件、4个CSS文件、2个Markdown文档、2个JPG图片文件、1个gitignore文件和1个SVG文件。该项目简洁易用,采用的技术经典,非常适合Java项目入门学习和企业级Java开发熟悉,提供了二手书交易管理、用户认证、数据统计等功能,旨在为校园内的二手书交易提供一个便捷、安全的平台。

    基于SSM的旅游管理系统.zip

    基于SSM的旅游管理系统.zip

    基于ssm框架网络财务设计与实现.zip

    基于ssm框架网络财务设计与实现.zip

    三菱PLC例程源码PLC同变频器通讯程序3

    三菱PLC例程源码PLC同变频器通讯程序3本资源系百度网盘分享地址

    基于ssm+jsp网上茶叶销售平台.zip

    基于ssm+jsp网上茶叶销售平台.zip

    通信专业毕业设计(论文)-企业网通信方案设计

    随着网络和科学技术的飞速发展,网络建设作为信息化建设的基础,也越来越受到企业的重视,网络结构和网络信息安全都是企业信息化建设中需要解决的重要问题。 本设计出于对众宇通讯公司长期稳定发展的考虑,针对公司的现状和发展需求,为公司设计了一个稳定的、相对安全的、可扩展并且可以支撑必要的网络应用的网络结构。在此次设计中,主要的运用到的技术与实现功能有:(1)汇聚交换机上使用DHCP技术,使各个接入层设备可自动获取相应的IP地址,也避免了IP地址的冲突;(2)运用VRRP技术,增强网络的连续性和稳定性,实现多链路备份冗余和网关备份冗余;(3)运用MSTP技术,将不同的VLAN与相应实例捆绑,避免了网络环路和广播风暴的产生;(4)通过防火墙技术,实现了企业内部与外部网络之间的信息交互安全。除此之外,还进行了VLAN的划分,端口安全设置,ACL访问限制,NAT地址转换,使用OSPF协议、静态路由等网络配置。 本论文基于华为ENSP仿真模拟软件,充分考虑到了整个公司网络今后的实用性、安全性以及可扩展性。利用所学的相关知识和网络技术,对众宇通讯公司的网络进行模拟设计。此设计根据三层网络结构来搭建网络拓扑,

    Gromacs中文手册5.0.2.pdf

    Gromacs中文手册5.0.2

    三菱PLC例程源码八层以下货梯通用程序(奥菱达)

    三菱PLC例程源码八层以下货梯通用程序(奥菱达)本资源系百度网盘分享地址

    seg.v

    seg.v

    ftqqzx.zip

    ftqqzx.zip

    基于tensorflow深度学习的中文机器阅读理解-完形填空.zip

    人工智能毕业设计&课程设计

Global site tag (gtag.js) - Google Analytics