首页 LPC基础教程

LPC基础教程

举报
开通vip

LPC基础教程LPC基础教程 目 录 第一章: 编程环境基本介绍 1.1 UNIX 基本结构 ................................................................................................... 1 .2 UNIX 基本命令 ................................................................................................... 1...

LPC基础教程
LPC基础教程 目 录 第一章: 编程环境基本介绍 1.1 UNIX 基本结构 ................................................................................................... 1 .2 UNIX 基本命令 ................................................................................................... 1 1 第二章: LPC 程序及其资料形态 ....................................................................................... 2 2.1 程序特点 ............................................................................................................ 2 2.2程序的即时性 ...................................................................................................... 2 2.3 电脑是怎样认识程序的 ....................................................................................... 3 2.4 LPC 的资料型态.................................................................................................. 3 第三章: 函数 (functions) .................................................................................................. 3 3.1 什麽是函数? ....................................................................................................... 3 3.2 外部函数 (efuns) ................................................................................................. 4 3.3 如何定义你自己的函数 ....................................................................................... 4 第四章: 基础的继承 ......................................................................................................... 4 4.1 从一个小程序开始 .............................................................................................. 4 4.2 物件导向程式设计(object oriented programming) ................................................... 5 3 继承的作用 ......................................................................................................... 5 4. 第五章: 变数 (variable) 处理 ........................................................................................... 5 5.1 数值与物件 ......................................................................................................... 5 5.2 区域 (local) 和全域 (global) 变数 ....................................................................... 6 5.3 处理变数的值 ..................................................................................................... 6 5.4 复杂的运算式 ..................................................................................................... 6 5.5 LPC 运算子......................................................................................................... 7 第六章: 流程控制 (flow control) ....................................................................................... 9 6.1 LPC 流程控制叙述 .............................................................................................. 9 6.2if() ...................................................................................................................... 10 6.3 while() 和 do {} while()...................................................................................... 12 6.4 for() 回圈 .......................................................................................................... 12 6.5叙述: switch() ..................................................................................................... 13 6.6 改变函式的流程和流程控制叙述 ....................................................................... 14 第七章: 网络编程 .......................................................................................................... 16 7.1 Socket 模式 ----------- ................................................................................... 16 7.2创建 Socket ----------- ................................................................................... 18 7.3 客户端/服务器模型 ----------------- ............................................................ 19 7.4 绑定到一个端口 --------------...................................................................... 20 7.5 安全 ----......................................................................................................... 21 7.6 监听连接 --------........................................................................................... 22 编后语 ........................................................................................................................... 23 I MUD是一种网络游戏,是英文Multiple User Dimension、Multiple User Dungeon或Multiple User Dialoguede 缩写,可以翻译为多人世界,多人地下城或多人对话,我们俗称为“泥巴”。 MUD的基本部分是运行于UNIX系统上,其实现编译语言就是将要介绍给您的LPC语言。其实,如果您已经对UNIX的一些基本指令有所了解的话,exp:ls,mkdir,rm,mv,cp等等,那么您应该知道如何进入一个mud中的文字编译环境,编一个小程序并存储它了。这里还需要说明一下,那就是lpc编译出的语言在结构上非常类似于我们所学的C语言编译程序,但是lpc与C语言还是有相当的差距的。总之,我想说明的意思就是关键是要掌握编程的核心,即编译原理,知道了原理和方法,程序指令是死的,只要多下工夫,是能够弄好弄精的。这里,我想通过初级篇和进阶篇的一些内容来向您说明LPC以及怎样运用这门语言,不过程序是要多实践的,光通过材料来学习还是不行的,多看看代码,多编些东西,多动手实践一下就会越来越熟悉它了。 本教程选取的是Descartes of Borg于1993年编写的基础lpc和中级lpc教程的内容.在这些教材的基础上我做了一些改动,以供您更方便容易的学习LPC这门语言. 第一章: 编程环境基本介绍 1.1 UNIX 基本结构 Mudlib编程语言lpc 使用的是基本的 UNIX 命令及档案结构,因此我们有必要想了解一下UNIX方面的知识和相关内容.与我们常用的DOS系统一样, UNIX 也使用阶层式的目录结构. 所有的次目录都附属于根目录之下. 而每个次目录之下同样可以有更多的次目录. 一个目录可以有两种表示方法: 1) 用目录的全名 (full name), 或称作绝对名称 (absolute name). 2) 使用相对名称 (relative name). 绝对名称就是从根目录一路写下来, 直到该目录的名字为止.exp:/daemon/skills/sword.c 就是根目录下daemon目录下的 skills目录下的sword.c程序.相对名称使用的是相对於其他目录的名字. 以上面的例子来说, 相对於/daemon,存在目录skills,不难得出,绝对目录是从根目录开始的,而相对目录则灵活的多,随便一个几极的子目录都可以成为确定另一个目录的相对根目录.这里还要确定一下,上述举例中的/daemon/skills/我们都称为路径,而sword.c就是我们所说的档案名。怎么样,和DOS差不多吧,其实树形目录结构是很多系统共同的部分。 1.2 UNIX 基本命令 LPmud使用许多UNIX的指令,比较典型的指令有:ls,cd,rm,mv,edit等等.这些指令对于我们维护和使用LPC的编程环境是非常有用的.这里先举一些常用的指令供您参考: pwd 显示你目前所在的工作目录. 1 cd 改变你目前的工作目录. ls 列出一个目录里面所有的档案.(相当于DOS中的dir) rm 删除指定的档案.(相当于DOS中的del) mv 更改指定档案的档案名.(相当于DOS中的rename) cp 拷贝一个档案到指定目录的命令.(相当于DOS中的copy) mkdir 建立一个新的目录.(相当于DOS中的md) rmdir 删除一个目录,不过该目录必须是空目录.(相当于DOS中的rd) more 如果一个程序太长了,使用这个指令可以分页显示该档案代码.(相当于 DOS中的type|more) edit 进入编程模式的指令. 从上面的初次接触中我们不难发现,无论是环境还是指令和我们常用的系统都是差不多的,原理是一样的。 第二章: LPC 程序及其资料形态 2.1 程序特点 我们使用LPC编写程序的所写的内容可以统称为物件(objects).一般来说,我们运行一个程序的时候,是有开始和结束的.换句话说,就是所有的程序开始执行的时候,总有一个开头的地方和结束的地方,程序执行后就终止了.而LPC的程序不同,整个mudlib的driver系统运行的是我们用LPC编写出来的一个个程序,这些程序在不同的时间和情况下被不断的调用,虽然都是运行程序,但是LPC的程序在mudlib中是不存在绝对的触发点和结束点的。这一点需要我们注意。 2.2程序的即时性 本来整个mud游戏可以全部用C语言来写.这样游戏的执行速度将会快上很多, 然而这样却让mud缺乏可塑性,使巫师在游戏正在执行的时候无法即时加入新东西.DikuMUD就是全部用C语言写成的.而LPMUD的理论就是driver不该决定游戏内容,而游戏内容应该决定于游戏中的个别事物,并能够在游戏执行时加上东西.这就是为什麽LPMUD使用LPC程式语言.它能让你用LPC定义游戏内容,交给主运行系统根据需要读取并执行.当我们用LPC写了一个程序(假设是用正确的LPC),当你上传(send)成功后,一旦游戏中的东西参考它,他就会即时发生作用.这就是使用LPC语言做到的即时性编程效果. 2 2.3 电脑是怎样认识程序的 我们使用的任何一种编程语言,电脑都不能直接接受它,必须通过转化才行.电脑语言是由0与1组成的一系列排列有序的代码组成的.而我们所用的BASIC、C、C++、Pascal等等,这些电脑语言全都是过渡语言. 这些电脑语言让你能把想法组织起来, 让思考更易转换成电脑的 0 与 1 语言.而转换是通过我们常挂在嘴边所说的编译来实现的.不过对于不同类型的数据,电脑把他转化过来存储起来的时候将不是直接的0和1的形式,就是说,每一个LPC变量都有变量型态指导如何转换资料.比方说我们事先说明int x,就是说明x是一个整形的量值,通过对资料形态的说明,可以让电脑明白每组0,1系列的数据的明确意思. 2.4 LPC 的资料型态 LPMud driver具有以下的资料型态: void,status,int,string,object,int *,string *,object *,mixed *有一些资料型态是我们经常使用的,具有非常重要的作用: float,mapping float *,mapping *.现在我们所用的LPmud的driver一般都是MUDOS,其中的资料形态和上面所例举的差不多. 第三章: 函数 (functions) 3.1 什麽是函数? 同任何函数一样,LPC函数获得输入值,然后返回输出值.记得Pascal语言是把过程(procedure)和函数区分开来.LPC并不这样做,采用另外一种形式来区分.Pascal称为过程的东西,在LPC就是无返回值(void)型态的函数.也就是说,程序或无返回值函数不传回输出值.Pascal称为函数的东西,就是有传回输出值的.在LPC里,最短的正确函式是:void do_nothing(){},这个函数不接受输入,没有任何指令,也不传回任何值. 要写出正确的 LPC 函数有三个部分: 1) 宣告 (declaration) 2) 定义 (definition) 3) 呼叫 (call) 就像变数一样, 函数也要宣告. 这样一来, 就可以让我们的driver知道: 1) 函数输出的资料是什麽型态 2) 有多少个输入的资料以及它们的型态为何. 比较普通的讲法称这些输入值为参数.所以,宣告一个函数的格式如下: 返回值型态 函数名称 (参数 1, 参数 2, ..., 参数 N);这样是形式我们在很多编程语言中都遇见过,所以是不难理解和运用的.需要说明一点的是: 哪一个函数定义在前都没有关系. 这是因为函数并不是由前往后连续执行的. 函数只有被呼叫时才会执行. 唯一的要求是, 一个函数的宣告必须出现在函数的定义之前, 而且也必须在任何函数定义呼叫它之前.我们不妨举出write_vals() 和 add()两个函数的例子,仅供参考: /* 首先, 是函式宣告. 它们通常出现在物件码的开头. */ void write_vals(); int add(int x, int y); /* 接着是定义 write_vals() 函式. 我们假设这函式将会在物件以外被呼叫. */ void write_vals() { int x; /* 现在我们指定 x 为呼叫 add() 的输出值. */ x = add(2, 2); 3 write(x+"\n"); } /* 最後, 定义 add() */ int add(int x, int y) { return (x + y); } 3.2 外部函数 (efuns) 也许你已经听过有人提过外部函数.它们是外部定义的函数.外部函数是由mud driver所定义.如果您已经编写LPC程序代码很久, 那么实际上您已经接触到了很多函数,exp: this_player(), write(), say(), this_object()...等等,这些看起来很像函数的式子其实就是外部函数.外部函数的价值在于它们比LPC函数要快得多, 因为它们是事先就以电脑可以直接读取和运行的二进制码的格式存在着.这些外部函数是早就被定义和宣告好的内容,需要时您只需要直接呼叫调用它们就可以了. 创造外部函数是为了处理普通的、每天都需要使用到的函数呼叫、处理 internet socket 的输出与输入、其他用LPC难以处理的事情的完成和实现.它们是在 driver 内以 C 写成的, 并与 driver 一起编译在 mud 开始之前, 这样它们执行起来会快得多. 但是对您来说, 外部函数呼叫就像对您的函数呼叫一样,它们还是需要知道两件重要的事: 1) 它的返回值是什么, 2) 它需要什么参数. 外部函数的详细资料及其形态,可以在你的 mud 中的 /doc/efun 目录找到. 不过因为每种 driver 的外部函数都不相同,所以无法给出一个详细的类型表分类,不过,你可以通过「man」或「help」指令 (视 mudlib 而定) 找到详细的资料. 例如指令「man write」会给你 write 外部函式的详细资料.当然,「more /doc/efun/write」也可以. 3.3 如何定义你自己的函数 虽然在档案中, 函数次序的先后是没有什么关系的, 但是定义一个函数的程式代码的先后顺序却非常重要.当一个函数被呼叫时, 函数定义中的程式代码按照出现的先后顺序执行. 例如在4.1中的 write_vals() 中, 这个指令: x = add(2, 2); 如果你想看到 write() 使用正确的 x 值, 就必须把它放在 write() 呼叫之前. 函数要返回一个值时, 由「return」指令之后跟着与函数相同资料型态的值来完成返回. 在先前的 add() 之中, 指令「return (x+y);」把 (x+y) 的值传回给write_vals()并指定给 x.也就是说「return」停止执行函数, 并返回程式代码执行的结果给呼叫此函数的另一个函数.另外,它将跟在它后面任何式子的值传回呼叫的函数. 因此,要停止执行失去控制的无返回值函数, 使用 return就可以了; 而后面不应加上任何东西. 这里需要提醒您一点的是,使用「return」传回任何函数的资料型态必须与函数式本身的资料型态相符合,这是一一对应的关系. 第四章: 基础的继承 4.1 从一个小程序开始 我们来看下面这个小程序,它实现的是一个房间: inherit ROOM; void create() {set("short","日月园"); set("long", "这是江南的工作室,其实就是一个盛开着各种花卉的小花园\n"); 4 set("exits", ([ "down":"/d/xyj/kezhan", "north":"/u/power/doorroom", ])); setup(); } 从这个简单的程序中,我们不难得出以下几点也存在几个问题: 1) create() 是函数的定义. 2) 它呼叫set()、set_exits(), 而这两个函数在这段程序代码中并没有宣告或定义. 3) 最上面有一行, 不是宣告变数或函式, 也不是函式定义 ! 问题: 1) 为什麽没有宣告 create() ? 2) 为什麽set() 、set_exits() 已经宣告并定义过可以直接使用了? 3) 程序最上面一句话究竟是什么意思,产生什么作用呢? 这就是本章将要介绍的基础的继承,下面我们开始. 4.2 物件导向程式设计(object oriented programming) 继承(inheritance)是定义真正物件导向程式设计的特性之一. 它让你创造通用的程式码, 能以多种用途用於许多不同的程式中.一个 mudlib 所作的,就是创造这些通用的档案(物件), 然后我们通过调用这些档案来帮助我们制造特定物件. 如果你必须把定义前面工作室全部所需要的程式码写出来,大概必须要写 1000 行程式码才能得到一个房间所有的功能.显然那是不切实际的. 再者,这种程式码与玩家和其他房间的互动性很差, 因为每一个创造者都写出自己的函式以作出一个房间的功能. 所以, 你可能使用 query_long() 写出房间的长叙述, 其他的巫师可能使用 long() . 这就是 mudlib 彼此不相容最主要的原因, 因为它们使用不同的物件互动协定. 因此OOP的出现克服了这些问题.前面的工作室中,inherit ROOM表示你已经继承了ROOM的函数ROOM拥有普通房间所需要的全部函式定义其中. 当你要制造一个特定的房间, 你拿这个房间档案中定义好的通用函式功能, 并加上你自己的函式create()就可以很轻松地制造一个独特的房间. 4.3 继承的作用 例举上面这个房间的例子,inherit ROOM使你调用出了ROOM这个已经宣告好的函数,该函数包含了许多房间函数,如set()和set_exit()等等,正是基于这些函数都是实现宣告并定义好的,所以我们可以直接利用它们来进行我们的代码编辑工作.在你的 creat() 函式里, 你呼叫那些函式来设定你房间一开始的值. 这些值让你的房间不同於别的房间, 却保留与记忆体中其他房间互动的能力. 由于mudlib之间还存在差异性,所以不同的mudlib就各有一套不同的 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 函数供我们使用,例如F_SSERVE和SSERVE其实是同一个标准函数.因此在coding之前我们需要弄清楚我们所处的mudlib的环境以及提供的标准函数的一些具体情况再开始编程. 第五章: 变数 (variable) 处理 5.1 数值与物件 基本上, mud 里头的物件都不一样的原因有两个: 1) 有的物件拥有不同的函式 5 2) 所有的物件都有不同的数值 现在,所有的玩家物件都有同样的函式.它们不一样的地方在於它们自己所拥有的数值不同(例如id),举例来说,名字叫做mzjl的玩家跟fyfbi,他们各自的name变数值不同,一个是"mzjl",另一个是"fyfbi". 所以, 游戏中量值地改变伴随着游戏中物件值的改变.函式名称就是用来处理变数的过程名称. 例如说,create()函式就是特别用来初始化一个物件的过程. 函式之中, 有些特别的事称为指令. 指令就是负责处理变数的. 5.2 区域 (local) 和全域 (global) 变数 跟大多数程式设计语言的变数一样, LPC 变数可以宣告为一个特定函式的「区域」变数, 或是所有函式可以使用的「全域」变数. 区域变数宣告在使用它们的函式之内. 其他函式并不知道它们存在, 因为这些值只有在那个函式执行时才储存在记忆体中. 物件码宣告全域变数之後, 则让後面所有的函式都能使用它. 因为只要物件存在, 全域变数就会占据记忆体. 你只有在整个物件中都需要某个值的时候, 才要用全域变数. 看看下面两段程式码: int x; int query_x() { return x; } void set_x(int y) { x = y; } void set_x(int y) { int x; x = y; write("x 设定为 "+x+" 并且会消失无踪.\n"); 第一个例子里, x 宣告在所有的函式之外, 所以在 x 宣告之後的所有函式都能使用它. x 在此是全域变数. 第二个例子中, x 宣告在 set_x() 函式里. 它只有在 set_x() 执行的时候存在. 之後, 它会消失. 在此, x 是区域变数. 5.3 处理变数的值 给 driver 的指令 (instruction) 用来处理变数值. 一个指令的范例是: x = 5; 上面的指令很清楚. 它把 5 这个数值指定给 x 变数. 不过, 这个指令牵涉到一些对普通指令来说很重要的观念. 第一个观念是运算式,一个运算式就是有值的一系列符号. 在上面的指令中, 运算式 5 的值指定给变数 x.常数是最简单的运算式.一个常数就是不变的值, 像是整数 5 或是字串 "hello". 最後一个观念就是运算子.在上面的例子中,使用了 = 这个指定运算. 在 LPC 有更多其他的运算子, 还有更复杂的运算式. 如果我们进入一个更复杂的层次, 例如: y = 5; x = y +2; 第一个指令使用指定运算子以指定常数运算式5的值给变数y.第二个指令把(y+2)的值以加法运算子把y和常数运算式2加起来,再用指定运算子指定给x. 换另一种方法来讲, 使用多个运算子可以组成复杂的运算式. 在前面的范例中, 一个指令 x = y + 2; 里面含有两个运算式: 1) 运算式 y+2 2) 运算式 x = y + 2 5.4 复杂的运算式 前面你大概已经注意到, 运算式 x = 5 「本身」也有个值是 5. 实际上, 因为 LPC 运算子如同运算式一样也有自己的值, 它们能让你写出一些非常难解、看起来毫无意义的东西, 像是: i = ( (x=sizeof(tmp=users())) ? --x : sizeof(tmp=children("/std/monster"))-1) 6 基本上只是说: 把外部函式 users() 传回的阵列指定给 tmp, 然後把此阵列元素的数目指定给 x. 如果指定给 x 的运算式值为真 (不是 0) , 就指定 x 为 1 并指定 i 的值为 x-1 的值. 如果 x 为伪, 则设定 tmp 为外部函式 children() 传回的阵列, 并指定 i 为阵列 tmp 的元素数目再减 1. 你曾经用过以上的叙述吗 ? 我很怀疑. 不过你可能看过或使用与它相似的运算式, 因为一次合并这麽多的东西在一行里面, 能提升你程式码的执行速度. 比较常使用 LPC 运算子这种特性的写法大概像这样: x = sizeof(tmp = users()); while(i--) write((string)tmp[i]->query_name()+"\n"); 取代这样子的写法: tmp = users(); x = sizeof(tmp); for(i=0;iquery_name()+"\n"); 像是 for()、while() 、阵列......等等东西稍後会解释. 不过第一段程式码比较简洁, 执行起来也比较快. 下面提供一些LPC运算子的说明. 5.5 LPC 运算子 = 指定运算子 (assignment operator): 范例 x = 5 说明:把「右边」任何运算式的值指定给它「左边」的变数. 注意, 你只能於左边使用一个变数, 也不能指定给常数或复杂的运算式. + 加法运算子 (addition operator): 范例 x + 7 左边值加上右边值的总和 说明:把右边运算式的值加上左边运算式的值. 对整数 (int) 型态值来说, 就表示数值总和.对字串(string)来说,表示右边的值接在左边的值後面("a"+"b"的值是 "ab"). 这个运算子不改变任何原始值 (即变数 x 维持原来的值). - 减法运算子 (subtraction operator): 范例 x - 7 左边运算式的值减去右边的 说明:虽然它是减法, 但实际上与加法的特性是相同的. 字串 "ab" - "b" 的值是 "a". * 乘法运算子 (multiplication operator): 范例 x*7 说明:除了这个作数学乘法之外, 特性与加法、减法相同. / 除法运算子 (division operator): 范例 x/7 值与说明 同上 += 加法指定运算子(additive assignment operator): 7 范例 x += 5 值与 x + 5 相同 说明:它把左边的变数值和右边的运算式值加起来, 把总和指定给左边的变数. 例如 如果 x = 2... x += 5 指定 7 值给变数 x. 整个运算式的值是7. -= 减法指定运算子 (subtraction assignment operator): 范例 x-=7 值:左边的值减去右边的值. 说明:虽然执行的是减法运算, 但特性与 += 相同. *= 乘法指定运算子 (multiplicative assignment operator): 范例 x *= 7 值:左边的值乘上右边的. 说明:除了乘法以外, 与 -= 和 += 相似. /= 除法指定运算子 (division assignment operator): 范例 x /= 7 值:左边变数的值除以右边的值. 说明:除了除法以外, 同上. ++ 後,前增加运算子 (post/pre-increment operators): 范例 i++ 或 ++i 值:i++的值是i,++i的值是i+1. 说明:++ 改变 i 的值, 将 i 加上 1. 但是, 运算式本身的值是多少, 要看你把 ++ 摆在哪里. ++i 是前增加运算子. 这表示它的增加在给予值「之前」. i++ 是後增加运算子. 它计算在 i 增加之前. 重点在哪 ? 好, 目前这对你来说无关紧要, 但是你应该记住它代表的意思. -- 後,前减少运算子 (post/pre-decrement operators): 范例 i-- 或 --i 值:i-- 的值是 i --i 的值是 i 减掉 1. 说明:运算特性同++. == 相等运算子 (equality operator): 范例 x == 5 值:真或伪 (非 0 或 0) 说明:它不更改任何值, 但是 如果两个值相等就传回真. 如果两边不相等则传回伪. != 不等运算子 (inequality operator): 范例 x != 5 值:真或伪 说明:如果左边的运算式不等於右边的运算式就传回真. 如果它们相等则传回伪. > 大於运算子 (greater than operator): 范例 x > 5 8 值:真或伪 说明:只有在 x 大於 5 时为真 如果相等或小於就为伪 < 小於运算子 (less than operator) >= 大於或等於运算子 (greater than or equal to operator) <= 小於或等於运算子 (less than or equal to operator): 范例 x < y x >= y x <= y 值:真或伪 说明:与 > 相似,除了<如果左边小於右边就为真>=如果左边大於「或等於」右边则为真<=如果左边小於「或等於」右边就为真 && 逻辑与运算子 (logical and operator) || 逻辑或运算子 (logical or operator): 范例 x && y x || y 值:真或伪 说明:如果右边的值和左边的值是非零值, && 为真. 如果任何一边是伪, 则 && 为伪. 对 || 来说, 只要两边任何一个值是真, 则为真. 只有两边都是伪值时, 才为伪. ! 否定运算子 (negation operator) 范例 !x 值:真或伪 x 为伪, !x 就为真. 说明:如果 x 为真, 则 !x 为伪 如果 -> 呼叫运算子 (the call other operator) 范例 this_player()->query_name() 值:被呼叫函式的传回值 说明:它呼叫右边这个函式, 而这个函式位於运算子左边的物件之内. 左边的运算式「必须」是一个物件, 而右边的运算式「必须」是函式的名字. 如果物件之中没有这个函式, 它会传回 0 (更精确一点, 没有定义 (undefined) ). ? : 条件运算子 (conditional operator) 范例 x ? y : z 值:上面的例子里, 如果 x 为真, 其值为 y 如果 x 为伪, 其值为运算式 z 说明:如果最左边的值为真, 这整个运算式的值就是中间的运算式. 不然, 就把整个运算式的值定为最右边的运算式. 第六章: 流程控制 (flow control) 6.1 LPC 流程控制叙述 if(运算式) 指令; if(运算式) 指令; else 指令; if(运算式) 指令; 9 else if(运算式) 指令; else 指令 while(运算式) 指令; do { 指令; } while(运算式); switch(运算式) { case (运算式): 指令; break; default: 指令; } 我们讨论这些东西之前,先谈一下什麽是运算式和指令.运算式是任何有值的东西,像变数、比较式(像 x > 5, 如果x是6或6 以上, 则其值为 1, 不然其值为 0)、指定式 (像 x += 2). 而指令是任何一行单独的 LPC 码, 像是函式呼叫、值指定式 (value assignment)、值修改式 (value modification) ......等等. 你也应该知道 && 、||、==、!=、! 这些运算子. 它们是逻辑运算子. 当条件为真时, 它们传回非零值, 为伪时则传回 0. 底下是运算式值的列表: (1 && 1) 值: 1 (1 和 1) (1 && 0) 值: 0 (1 和 0) (1 || 0) 值: 1 (1 或 0) (1 == 1) 值: 1 (1 等於 1) (1 != 1) 值: 0 (1 不等於 1) (!1) 值: 0 ( 非 1) (!0) 值: 1 ( 非 0) 使用 && 的运算式中, 如果要比较的第一项测试值为 0, 则第二项永远不会测试之. 使用 || 时, 如果第一项为真 (1), 就不会测试第二项. 6.2if() 我们介绍第一个改变流程控制的运算式是 if(). 仔细看看底下的例子: 1 void reset() { 2 int x; 3 4 ::reset(); 5 x = random(100); 6 if(x > 50) set_search_func("floorboards", "search_floor"); 7 } 每一行的编号仅供参考. 在第二行, 我们宣告一个称为 x 的整数型态变数. 第叁行则优雅地留下一行空白, 以明示宣告结束和函式码开始的界线. 变数 x 只能在 reset() 函式中使用. 第四行呼叫 room.c 中的 reset(). 第五行使用 driver 外部函式的 random() 以传回一个随机数字, 此数字介於 0 到参数减一. 所以在此我们想得到一个介於 0 到 99 的数字. 第六行中, 我们测试运算式 (x>50) 的值, 看它是真是伪. 如果为真, 则呼叫 room.c 的函式 set_search_func(). 如果为伪, 就不可能执行呼叫 set_search_func() . 10 第七行, 函式将 driver 的控制权交回呼叫此函式的函式 (在这个例子中, 呼叫 reset() 的是 driver 自己) , 也没有传回任何值. 如果你想执行一个以上的指令, 你必须按照以下的方法来做: if(x>50) { set_search_func("floorboards", "search_floor"); if(!present("beggar", this_object())) make_beggar(); } 注意运算式为真时, 要执行的指令以 {} 包围起来. 这个例子里, 我们再次呼叫 room.c 中的 set_search_func() 来设定一个函式 (search_floor()) , 这个函式稍後被你设定为: 玩家输入 "search floorboards" 时, 呼叫 search_floor(). (注: 这种例子要看 mudlib 而定. Nightmare 有这个函式呼叫, 其他 mudlib 可能会有类似的东西, 也可能完全没有这一类用途的函式) 接着, 另一个 if() 运算式检查 (!present("beggar", this_object())) 运算式是否为真. 测试运算式中的 ! 改变它後面运算式的真伪. 在此, 它改变外部函式 present() 的真伪值. 在此, 如果房间里有个乞丐, present() 就传回乞丐这个物件 (this_object()), 如果没有乞丐, 则传回 0. 所以, 如果房间里面还有个活乞丐, (present("beggar", this_object())) 的值就会等於乞丐物件 (物件资料型态) , 不然它会传回 0. ! 会把 0 变成 1 , 把任何非零值 (像是乞丐物件) 变成 0. 所以, 房间里没有乞丐时, 运算式 (!present("beggar", this_object())) 为真, 反之, 有乞丐为 0. 如果房间里没乞丐, 它呼叫你房间码中定义的函式来制造一个新的乞丐, 并放进房间. (如果房间中已经有一个乞丐, 我们不想多加一个 :) ) 当然, if() 常常和一些条件一起出现 :). LPC 里, if() 叙述的正式写法为: f(运算式) { 一堆指令 } else if(运算式) { 一堆指令 } else { 一堆指令 } 这样表示: 如果运算式为真, 执行这些指令. 不然, 如果第二个运算式为真, 执行第二堆指令. 如果以上皆伪, 执行最後一堆指令. 你可以只用 if() : if(x>5) write("Foo,\n"); 跟着一个 else if(): if(x > 5) write("X 大於 5.\n"); else if(x >2) write("X 小於 6, 大於 2.\n"); 跟着 else: if(x>5) write("X 大於 5.\n"); else write("X 小於 6.\n"); 或是把上面列出来的东西全写出来. 你有几个 else if() 都没关系, 但是你必须有一个 if() (也只能有一个), 也不能有一个以上的 else . 当然, 上面那个乞丐的例子中, 你可以在 if() 叙述中重复使用 if() 指令. 举例来说, if(x>5) { if(x==7) write("幸运数字 !\n"); else write("再试一次.\n"); } else write("你输了.\n"); 11 6.3 while() 和 do {} while() 原型: while(运算式) { 一堆指令 } do { 一堆指令 } while(运算式); 这两者让你在运算式为真时, 一直重复执行一套指令. 假设你想设定一个变数等於玩家的等级, 并持续减去随机的金钱数量或可承受伤害值 (hp, hit points) 直到该等级变数为 0 (这样一来, 高等级的玩家失去的较多). 你可能会这样做: 1 int x; 2 3 x = (int)this_player()->query_level(); 4 while(x > 0) { 5 if(random(2)) this_player()->add_money("silver", -random(50)); 6 else this_player()->add_hp(-(random(10)); 7 x--; 8 } 由於 x 本身稍後会一直减 1 直到到 x = 0 , 所以 x = 0 时也是伪值 (为 0). 第五行以 random(2) 随机传回 0 或 1. 如果它传回 1 (为真), (译注: 补充完毕) 则呼叫玩家物件的 add_money() 将玩家身上的银币随机减少 0 到 49 枚. 在第六行, 如果 random(2) 传回 0, 我们呼叫玩家物件中的 add_hp() 函式来减少 0 到 9 点的可承受伤害. 第七行里, 我们把 x 减 1. 第八行执行到 while() 指令的终点, 就回到第四行看 x 是否还大於 0 . 此回圈会一直持续执行到 x 小於 1 才结束. 但是, 你也许想在你执行一些指令「之後」再测试一个运算式. 比如用上面的例子, 如果你想让每个人至少执行到一次指令, 甚至还不到测试的等级: int x; x = (int)this_player()->query_level(); do { if(random(2)) this_player()->add_money("silver", -random(50)); else this_player()->add_hp(-random(10)); x--; } while(x > 0); 这个例子真的很奇怪, 因为没几个 mud 会有等级为 0 的玩家. 而且, 你可以修改前面例子中的测试条件做到同样的事. 不管如何, 这个例子只是要展现出do {} while() 的如何工作. 如你所见, 此处在回圈开始的时候没有初始条件 (在此不管 x 的值为何, 立刻执行) , 回圈执行完之後才测试. 这样能保证回圈中的指令至少会执行一次, 无论 x 为何. 6.4 for() 回圈 原型: for(初始值 ; 测试运算式 ; 指令) { 指令 } 12 初始值: 让你设定一些变数开始的值, 用於回圈之内. 此处可有可无. 测试运算式: 与 if() 和 while() 的运算式相同. 当这一个 (或一些) 运算式为真时, 执行回圈. 你一定要有测试运算式. 指令: 一个 (或一些) 运算式, 於每个回圈执行完毕之後执行一次. 此处可有可无. 注: for(;运算式;) {} 与 while(expression) {} 「 完 全 相 同 」 范例: 1 int x; 2 3 for(x= (int)this_player()->query_level(); x>0; x--) { 4 if(random(2)) this_player()->add_money("silver", -random(50)); 5 else this_player()->add_hp(-random(10)); 6 } 这个 for() 回圈与前面 while() 的例子「完全相同」. 还有, 如果你想初始化两个变数: for(x=0,y=random(20);xquery_name(); switch(name) { case "descartes": write("You borg.\n"); case "flamme": case "forlock": case "shadowwolf": write("You are a Nightmare head arch.\n"); default: write("You exist.\n"); } 对我来说, 我会看到: You borg. You are a Nightmare head arch. You exist. Flamme、Forlock 、或 Shadowwolf 会看到: You are a Nightmare head arch. You exist. 其他人会看到: You exist. 6.6 改变函式的流程和流程控制叙述 以下的指令: return continue break 能改变前面提过的那些东西, 它们原本的流程. 首先, return 一个函式中, 不管它出现在哪里, 都会终止执行这个函式并将控制权交回呼叫这个函式的函式. 如果这个函式「不是」无传回值 (void) 的型态, 就必须在 return 叙述之後跟着一个传回值. 一个绝对值函式长得大概像这样: int absolute_value(int x) { if(x>-1) return x; else return -x; } 第二行里, 函式终止执行, 并回到呼叫它的函式. 因为在此, x 已经是正整数. continue 在 for() 和 while() 叙述中用得最多. 它停止目前执行的回圈, 把回圈送回开头执行. 例如, 你想要避免除以 0 的情况: x= 4; while( x > -5) { x-- if(!x) continue; write((100/x)+"\n"); } write("完毕.\n") 你会看到以下的输出: 14 33 50 100 -100 -50 -33 -25 完毕. 为了避免错误, 每一次回圈都检查 x, 确定 x 不为 0. 如果 x 是 0, 则回圈回到开头处的 测试运算式, 并不终止目前的回圈. 用 for() 运算式来说就是: for(x=3; x>-5; x--) { if(!x) continue; write((100/x)+"\n"); } write("完毕.\n"); 这样执行起来差不了多少. 注意, 这样子跟前面输出的结果一模一样. 当 x = 1, 它测试 x 是否为 0, 如果不是, 就显示 100/x, 然後回到第一行, 将 x 减 1, 再检查 x 是否是 0 , 如 果为 0, 回到第一行并把 x 再减 1. break 它停止执行流程控制叙述. 不管它出现在叙述里面的任何地方, 程式控制会结束回圈. 所以, 如果在上面的例子中, 我们把 continue 换成 break, 则输出的结果会变成像这样: 33 50 100 完毕. continue 最常用於 for() 和 while() 叙述. 但是 break 常用於 switch(). switch(name) { case "descartes": write("You are borg.\n"); break; case "flamme": write("You are flamme.\n"); break; case "forlock": write("You are forlock.\n"); break; case "shadowwolf": write("You are shadowwolf.\n"); break; default: write("You will be assimilated.\n"); } 下面这个函式跟上面的一样: if(name == "descartes") write("You are borg.\n"); else if(name == "flamme") write("You are flamme.\n"); else if(name == "forlock") write("You are forlock.\n"); else if(name == "shadowwolf") write("You are shadowwolf.\n"); else write("You will be assimilated.\n"); 但是 switch 叙述对 CPU 比较好. 如果这些指令放 15 在多层巢状 (nested) 的叙述中, 它们会改变最近的叙述. 你现在应该完全了解 if()、for()、while()、do{} while()、switch(), 也该完全了解如何使用 return、continue、break 改变它们的流程. 使用 switch() 要比一大堆 if() else if() 来得有效率, 所以应该尽量使用 switch() . 我们也向你介绍过怎麽呼叫其他物件中的函式.第六章的内容应该说是整个基础教程的关键,将这六章的内容结合起来,那么现在你已经能够做出简单的房间、NPC和其他简单的物件了,下面的事就是多琢磨,多钻研了. 第七章: 网络编程 在 MudOS 0.8.14 和 0.9.0 中的一个增强就是 Internet socket 功能被包含 进来了。MudOS 与 TMI 研究者一直希望使网络上 MUD 的更紧密地通过通信集 成在一起, Socket efun (或者 LPC socket) 依靠允许 LPC 开发者写作基于 Internet socket 的应用程序提供了第一级的 MUD 集成性。 例如,已经存在 用于 telnet、远程 MUD finger、远程 MUD tell、互联 MUD 邮件递送以及参 与 MUDWHO 系统的 LPC 物件。 之所以要写这么一份文档, 就是要把它作为一个指导你如何使用 LPC socket 进行基于网络的互联编程的指南。 它的定位将是那些有一定经验的 LPC 程序 员,他们已经理解 LPC 编程的大部分基础内容,但希望写一些基于网络的LPC 服务。 7.1 Socket 模式 ----------- 一共有五种不同的通信模式或者叫做套接字(socket)模式: MUD、STREAM、DATAGRAM、STREAM_BINARY,和 DATAGRAM_BINARY。这五种模式 的定义可以在 mudlib include 的 中找到。 MUD 模式 -------- MUD 模式是一个面向连接的通信模式, 这种模式中 LPC 数据类型可以由网络 从一个 MUD 传送到另一个 MUD。例如,在 MUD 模式中你可以发送结构数据— —如数组和映射——穿过网络到另一个也使用 MUD 模式 socket 的 MUD 中。 除 object 以外的所有的 LPC 数据类型都可以由 MUD 模式发送和接收。 jjgod 注:无法传送物件造成了穿越 mud 的功能, 比如一直比较热的分站漫 游功能受到一些阻碍,我们需要较为麻烦的获得一个物件身上所有 的变量(比如一个 USER_OB, 需要查找 /clone/user/user.c 以及 所有直接和间接继承——可以用 deep_inherit_list 得到——的 的文件中的变量),然后一个一个的发送和接收。 这样就造成兼容 性和可扩展性很成问题。 STREAM 模式 ----------- STREAM 模式也是一个面向连接的通信模式,和 MUD 模式不同的是,所有的数 据都是以字符串形式发送和接收的。所以,你可以通过 STREAM 模式从其他的 网络端(比如你自己写的一个 MUD 客户端)发送到 MUD 中。由于无法直接发送 16 和接收所有的 LPC 数据类型,STREAM 模式会显得不那么强大,但很多应用程 序,像 telnet,用不着发送整数、数组这样的数据, 而都是以各个方向的字 符流的形式浏览的。 MUD 模式 socket 其实就是使用特殊的代码以通过 STREAM 模式来实现发送和 接收 LPC 数据类型。因此,如果应用程序需要额外的数据提取,更适合用MUD 模式。 但 MUD 模式由于其固有的限制,将比 STREAM 模式更慢,也将使用更 注意,STREAM 模式是无法确保发送的字符串能够全部立即到达, 多的内存。 实际上它们是一份一份的送到后, 再将之重新组合在一起(每一份将按顺序到 达)。 DATAGRAM 模式 ------------- 和 MUD 与 STREAM 模式不同,DATAGRAM 模式是无连接的。你不需要确立一个 连接就可以在 MUD 间传输数据了。因此,每份数据是采用一种叫“datagram” 的数据包发送到目的地的,每个这种数据包都自带寻址信息,能够自觉地从网 络的一端行走到另一端。 因为 DATAGRAM 模式没有一个确定的连接,所以发出的 datagram 包有可能在 网络中就这么丢失了,没有任何一个 MUD 能收到它。 例如 TMI 用 DATAGRAM 模式发送的一个到 Portals 的数据包如果在网络中丢失了, Portals 可能永 远收不到它,而且完全不知道曾经发送过这么一个数据包。 而且 TMI 也无法 得知这个数据包是否丢失了,因为就算丢失了也不会收到任何错误信息。 TCP 和 UDP ---------- 在 MUD 模式和 STREAM 模式中,MUD 间将建立一个 TCP 连接,TCP 是一种能 够保证数据被正确发送的协议,如果它发现数据包丢失了,就会尝试重新发送 它,直到正确收到为止:它通过特定的算法来发送数据,这种算法使其能够估 算数据要花多长时间才能到达,如果过了那段时间还没收到回答,它就重新发 送一个数据包,直到收到确认信息为止。TCP 协议也确保了数据包能够按顺序 到达,而且也不会收到两个同样的数据包。(这是 TCP 协议的一点很肤浅的描 述,但也算简要地说明了为什么这种协议使得数据传输变为可信赖的。) DATAGRAM socket 则不然。 UDP 是一种面向 datagram 的协议,它在 MUD 间 发送数据包时是完全和“连接”、“重新发送”等这些词沾不上边的。但是, 既然 DATAGRAM 模式是不可靠的,为什么有人会用到它呢,当然,TCP 显得更 好:它通过重新发送确保了数据能够正确到达、它考虑到了网络中所有可能出 现的恶劣情况„„而实际上,不少应用程序却不在乎所有的数据是否正确到达 了另一端。你可能要问了,既然不在乎还发送它干什么,好吧好吧,这是个不 错的问题,但现在就回答它太早了, 你只要记住有些情况是得用到 DATAGRAM 模式的,我们会在后边详细的解释一下,别着急。 jjgod 注:例如 InterMud 这种松散集成的程序,就完全不用考虑数据包是否 正确发到了, 你的 MUD 有的时候甚至仅仅是毫无目的的在网上寻 找是否有能够互联的 MUD, 定时的 ping 也不期望别的 MUD 就一 定能收到——收不到就收不到呗,最多不过是少了一个与之互联的 MUD 而已,对自己没什么伤害。 相反,如果你与数百个 MUD 互联, 而和这些 MUD 之间传送信息都需要一次次的确认、 确认再确认, 网络负担就很可观了。 17 7.2创建 Socket ----------- 好的,让我们从创建一个 MUD 模式 socket 开始, 我们可以写这样一个物件 来实现: #include void create() { int s; s = socket_create(MUD, "close_callback"); if (s < 0) { write("socket_create: " + socket_error(s) + "\n"); return; } write("Created socket descriptor " + s + "\n"); socket_close(s); } void close_callback(int s) { write("socket " + s + " has closed\n"); } 让我们分解一下这个程序来看清楚一个 socket 是如何创建的。不过首先要说 的是,到我们能够用 socket 来发送数据还有一个漫长的路程要走,创建仅仅 是第一步呢。所以给点耐心吧,弄明白每个例子以后再开始做。 我们做的第一件事情就是 #include ,所有的 socket 定义都在这 个 socket.h 里面。首先是定义,例如 MUD、STREAM 和 DATAGRAM,虽然每个 名字都对应着一个数字,但写得好的程序应该用宏定义来代替数字:因为某天 你可能要修改这些定义(假如有一天 MUD 和 STREAM 代表的数字调换了,就不 必在代码中一处一处的修改数字), 也是因为这样可以让人一看就明白你打算 做什么。 我们定义了一个整数变量 s, 很多 socket 应用程序中 s 都作为 socket 的 缩写出现。然后我们以两个参数调用 socket_create(),第一个参数是socket 的模式(我们上面讨论的那些),注意我们使用宏定义 MUD 来代表 MUD 模式。 例子中第二个参数叫做关闭回叫函数, 当这个连接被关闭时就会由 MudOS 呼 叫此函数。 回叫(callback)常常被用在 LPC socket efun 中,以通知物件重 要网络事件的发生。注意,我们还可以以 STREAM 或 DATAGRAM 为第一个参数 来创建 STREAM 或 DATAGRAM socket。 所有的 socket efun 都会返回一个退出状态或者返回一个特定的值。 这个值 代表了此函数完整的状态。我们规定负值代表错误或者警告,当返回一个错误 代码时,应用程序得决定如何回答它。 有时假如 MUD 管理员不修改本地的配 置文件或者 MudOS 的话,根本没有可能获得成功的返回代码, 那怎么办呢, 比如说上面的例子,如果返回了错误(s 小于 0),我们就使用socket_error() 18 这个 efun 来在屏幕上显示出一段错误原因的信息,这在调试时是很有用的, 但在实际运行的时候,我们可能不希望所有的用户都看到这些杂乱的信息,所 以那时还是换成 log_file() 来把错误 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 下来,以备以后改正。 如果 socket_create() 成功了,它将返回一个大于等于 0 的整数,这个整数 代表了一个 socket、一个 socket 描述符(descriptor), 或者一个文件描述 符,这三个名字都源于 UNIX 术语。 如果 socket_create() 返回负值,就说 socket。 但这并不是获得一个错误的理由, 明有错误发生,没有创建出什么 实际上, 最常见的错误往往是因为指定错了 socket 模式造成的(如果你采用 socket.h 中的定义来指定,通常不那么容易出错,因为每个宏定义都很明显), 或者是 socket 溢出了。MUD 管理员可以通过配置 MudOS 能使用的 socket数 目来避免这个问题,默认这个数目是 16, 但你最好配置一下以适应自己 MUD 的需求,增加这个数字就可以使你能用到更多的 LPC socket 了。注意,每个 到达的 LPC socket 都将占用一个用于玩家登录和打开文件的 socket。 若你 需要同时保证大量的玩家和大量打开的 socket, 就得考虑增加这个最大值以 保证此进程能够打开足够多的文件描述符。 所有的 socket 物件都得小心不要丢失了 socket,socket 物件不像其他的 L PC 物件,它们的数目是有限的。 所以,如果我们在上面的例子中成功的创建 了一个 socket,后面一定要记住关闭它。 我们知道,丢失资源的轨迹称为“ 泄漏”,socket 泄漏发生在当一个物件创建了 socket,使用了一会儿却在不 再用到它的时候忘了关闭它,结果这个物件就一直占用着一个 socket, 别的 socket 物件只能看着干着急。不过如果一个物件被析构了,它那里的所有LPC 都会被自动关闭的。另一个值得注意的是,每个 socket 都有它独一无二的 s ocket 描述符(或者 socket 编号),因此如果某物件创建了一个 socket, 另 一个物件创建了第二个 socket, 这两个物件不可能收到相同的 socket 描述 符。我们可以利用这一点来实现一些功能,例如以 socket 描述符来作为一个 mapping 的索引(index)以记下每个打开的 socket 的信息。 但记住,如果一 个 socket 被关闭了,它就可以被 socket_create() 重新用到来作为新 soc- ket 的描述符。 jjgod 注:现在的 ES2 mudlib 中这些头文件似乎都移到了 /include/net 中。 如 socket 模式定义在 中,但 socket 错误的信 息定义在 中。 7.3 客户端/服务器模型 ----------------- 在继续介绍剩下的 socket efun 之前, 现在我们最好停下来复习一些基本的 网络概念。面向连接的通信常常是以客户端/服务器端模型构成的, 在这个模 型中,任何一个连接要么是客户端,要么就是服务器端。由客户端发起连接、 (向服务器端)请求一些服务。服务器端则是在等待客户端的连接请求,如果等 到了的话就提供相应的服务。例如 FTP 就是这么工作的。 用户通过连接到服 务器发出一个请求,服务器就会满足客户端的请求。服务器端和客户端不同之 处在于,它可能同时在为多个客户提供服务。 MUD 和 STREAM 就用到了客户端/服务器端模型, 客户端和服务器端采用些微 有点不同的方式来确立连接。后面我们还会讨论到使用 DATAGRAM 模式的点对 19 点(peer-to-peer)模型, 这种模型和客户端/服务器端模型也略微有点不同, 例如在确立连接时。 你也可以同时启用多个服务,每个服务都以一个“众所周知”或者说是“约定 俗成”的端口来区分。端口是从 1 到 65535 之间的一个整数,尽管如此,大 多数的 MUD 都采用 1025 到 65535 这个范围内的端口号,因为前 1023 个端 口都是为 telnet、ftp 这些已经成为标准的应用保留的。 要让客户端和服务 socket,将之帮定到一个约 器端之间能够进行通讯, 服务器端得先创建一个 定的端口上,然后监听连接的请求。另一方面,客户端也必须创建一个 sock- et,然后连接到那个约定的端口上。也就是说客户端将连接到服务器端所绑定 和监听着的那个端口。这就是为什么称之为“众所周知”端口的原因了,—— 客户端得先知道有这么个端口,才能去连接。约定的端口号往往定义在 Inte- rnet RFC 文档中,以一个大家认可的标准形式存在。 我们将在下面讨论如何通过执行 socket efun 来建立一个客户端与服务器端 的连接。不过在客户端能够发起一个连接请求之前,服务器端还需要做一些准 备工作,所以,先让我们启动服务器。 7.4 绑定到一个端口 -------------- 在服务器端用 socket_create() 创建了一个 socket 之后(而且当然返回值大 于等于 0),下一个合理的步骤是绑定到一个端口,这个工作是由 socket_bi- nd() 完成的。让我们在上面的例子里添加一点代码试试。 首先,声明一个新 的整数来记录呼叫错误,也就是那个 socket_bind() 的返回值啦。 int error; // 现在让我们添加一个到 socket_bind() 的呼叫: error = socket_bind(s, 12345); if (error != EESUCCESS) { write("socket_bind: " + socket_error(error) + "\n"); socket_close(s); return; } 这段内容要加在 socket_close(s) 之前。 那么,这有什么用呢,好吧,先看 第一个参数, 嗯,没什么奇怪的,就是我们从 socket_create() 那里得到的 socket 描述符。每个关于 socket 的呼叫都要用到这个描述符,以使得MudOS 明白我们想操作的是哪个 socket。 你还记得服务器端是经常同时运作超过一 个客户 socket 的吧,所以必须保证它们不被混淆。第二个参数很简单,就是 端口号,端口号必须为从 1024 到 65535 的整数,你看对不对, (其实 0 也 是合法的,我们会在稍后谈到这个。) 呼叫 socket_bind() 之后, 我们再检查一下返回值,看看是否发生了错误, 目前的情况下也就是和 EESUCCESS 比较一下,在绝大多数场合(socket_crea- te() 除外) EESUCCESS 都代表这个 socket efun 成功执行了。和 socket_c- reate() 类似,如果发生了错误,我们也使用 socket_error() 来将它以字符 串显示出来。那么输出错误以后我们就返回了,对不对,错了~上面我们提到 20 了泄漏这个词,如果我们就这么返回了,这个物件就会一直占用着这个不再被 用到的 socket 从而导致别人没法利用它。因此当我们确定以后不再用到这个 socket 时,千万记住关闭它。从 socket_create() 的呼叫开始,直到 sock- et_close() 被呼叫,这个 socket 都是打开的。因而,要做个良好的 socket 使用者,记住在你的工作完成时关闭它。 socket_bind() 有个挺有点“名气”的返回值——EEADDRINUSE。 为什么这么 socket 到 12345 端口, 然后另一个 socket 也 说呢,如果有人绑定了一个 尝试向绑定到同一个端口上,第二个 socket 的绑定将会失败。这很好理解, socket 绑定到一个端口之后,该端口就属于那个 socket 了, 其他试图掺和 进来的就会收到 EEADDRINUSE 这个错误信息。这是个很常见的错误。 正确的 解决 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 是:1) 检查一下是否同一个服务被启动了两次。 若是这样,关掉一 个,因为一个就够了。 2) 是否有几个的开发者为不同的服务选择了同一个端 口。这可不行,要避免这种情况可以让一个“端口管理员”来分配端口,其他 人不得插手。遗憾的是,网络不是孤立的,端口的分配需要所有你希望与之通 信的 MUD 都同意才行。 jjgod 注:在提到 EEADDRINUSE 错误描述符时, 作者用了“notorious(声名 狼藉的)”这个词,但在下文中并没有贬义, 所以就按照作者的本 意将之译为“名气”便罢。 7.5 安全 ---- 在继续下一步之前,我们需要回答几个关于非法的 socket 描述符的问题。当 我们传入的值是一个错误的 socket 描述符时,会怎样呢,别担心,MudOS 会 马上捕获你的行为,并告诉你这是行不通的。举个例子,当你传入一个小于 0、 或大于等于系统可用的 socket 最大值的描述符,MudOS 会发现你犯了个错误 并返回 EEFDRANGE。若你打算做得更狡猾一点的话,可以尝试给出一个合法但 却不是目前在用的数值,MudOS 还是会发觉并返回 EBADF。好吧,让我们再狡 猾一点,传入一个别的物件正在用的 socket 描述符。会怎么样呢,这就到了 解释为 LPC socket 建立的两层安全系统的时候了。 第一层的安全使用主控(master)物件来验证哪些物件可以、哪些物件不能使用 socket。 这可能在一些 MUD 中比较有用,例如我们打算让一些开发者有权限 使用 socket,而另一些没有, 或者出现个别的开发者滥用网络使用权而被禁 止使用 socket 的情况(后面的例子中那样的开发者最好让他离开算了)。为了 实现上述的意图,MudOS 调用了 valid_socket() 这个函数,valid_socket() 返回 0 或者 1 以标示请求的 socket 操作是否被允许。 如果没有 valid_s- ocket() 这么个函数存在,MudOS 就假定返回值是 0,这样所有的 LPC sock- et 操作将被全部禁止。所以,大多数的 MUD 的 master.c 都会包括下面这个 valid_socket(): int valid_socket(object eff_user, string fun, mixed *info) { return 1; } 第二层的安全更为严格些,它用于防止一个物件通过某些手段妨害其他的物件。 21 我们已经知道, 当一个 socket 创建时,呼叫 socket_create() 的那个物件 就等于拥有了这个 socket。每当一个 socket efun 被呼叫时,它都会比较一 下呼叫者是否那个拥有者。如果不同,这次呼叫 socket efun就被中断了。下 面有段很是可恶的代码: int s; for (s = 0; s < 100; s++) socket_close(s); 它并不会成功的关闭 MUD 中所有的 socket,而只能关闭所有这个呼叫者自己 拥有的那些 socket, 因为所有其他的 socket 都由第二层安全措施保护着呢。 如果被第一和第二层安全措施中的任一个拒绝,将返回 EESECURITY 来告诉那 位呼叫者:socket efun 因为安全原因拒绝了他的请求。如果你在写代码的过 程中遇到了这样的错误,多数是因为你传入了一个错误的 socket 描述符,毕 竟这偶尔是会出现的。 7.6 监听连接 -------- 当 socket 一创建出来,端口一被绑定,服务器就必须开始监听连接了。这是 由 socket_listen() 来完成的。和 socket_bind() 一样,一个参数是要监听 的 socket,第二个参数则是那个“监听回叫(listen callback)”函数。回忆 一下 socket_create() 中那个“关闭回叫”函数, socket_listen() 也指定 了一个当接到连接就会呼叫的函数,在这个函数中,服务器可以决定是接受这 个连接呢,还是关闭它。在大多数的服务器中,确实没有什么就这样关掉一个 连接的理由,因为这样通常过于武断,应该避免。若客户端和服务器端达成了 时,服务器端好歹应该返回一段消息,告诉客 某些鉴定的协议(例如密码检查) 户端为何连接被关闭了。当然,这可能更像风格的问题,但你得知道,要对一 个连上了马上就被莫名其妙地断开了的客户端或服务器端进行调试,是非常困 难的。如果你非得这么做的话,就要确保你在日志文件中记录下了关闭连接的 理由,这样管理员或者开发者才方便诊断原因,解决问题。 下面的代码,让一个已经创建了并绑定到端口上的 socket 开始进行连接监听: error = socket_listen(s, "listen_callback"); if (error != EESUCCESS) { write("socket_listen: " + socket_error(error) + "\n"); socket_close(s); return; } 这和上边的代码简直就是一样的么: 我们呼叫 socket_listen() 函数,检查 返回值看看是否成功了,若发生了错误则输出包括了指定错误描述的错误的信 息,然后,因为我们已经完成了工作,就关闭连接并返回。事实上,很多必需 的 socket 应用程序代码中都是按照这个模式写成的。 很明显,下一步就是讨论这个 listen_callback 函数,是吗, 按道理说没错, 但我们还是不这么做,而是换换空气,改为看点客户端的代码吧。理由很简单, 在客户端可以发起一个连接以前,讨论服务器端的问题太不现实了,因为这之 22 前服务器端并不会运行比上边更多的代码。因此,稍微离题一下,去讨论客户 端的问题是有必要的。 编后语 这个是总下载的,加入了自己的一些修改整理而成的一个LPC的学习文档,文档中难免有出错的地方,请指教。 ―――Larkin 小新 23 亲爱的朋友,上文已完,为感谢你的阅读,特加送另一篇范文, 如果下文你不需要,可以下载后编辑删除,谢谢, 道路施工方案 1、 工程概况 2、 编制说明及编制依据 3、 主要施工方法及技术措施 3(1施工程序 3(2施工准备 3(3定位放线 3. 4土方开挖 3(5卵石路基施工 3(6天然砾基层施工 3. 7高强聚酯土工格楞 3(8水泥稳定砂砾基层施工 3(9路缘石施工 3. 10玻璃纤维土工格栅施工 3(11沥青面层施工 3. 12降水施工 4、 质量控制措施 5、 雨季施工安排 6、 安全技术措施 1. 工程概况 本项目建设的厂址位于新疆石河子市。工程场地位于石河子高新技术开发区经七路西。场地原为麦田,地势南高北低。厂区道路连通各装置区域,并与经七路相连。 2. 编制说明及编制依据 为保质按时顺利完成厂区道路,根据工程施工招标文件、设计施工图,以及现场实际场地,并结合我公司多年来的现场施工经验编制此方案。 规范及标准: 《沥青路面施工技术质量规范》 JTG F40-2004 《工程测量规范》 GB50026-2007 《建筑施工安全检查标准》 JGJ59-1999; 3. 主要施工方法及技术措施 3.1施工程序 降水——施工测量——土方开挖——路基(卵石)整平——机械压 实——天然砂砾基层——机械压实——高强聚酸土工格楞——浆砌 卵石立缘石基础——水泥砂浆勾鏠——天然砂砾基层——机械压实 ——安装路缘石——水泥稳定砂砾底基层——玻璃纤维土工格楞 ——粗粒式沥青混凝土面层——中粒式沥青混凝土面层 3.2施工准备 熟悉图纸及规范,做好 技术交底 金刚砂技术交底断桥铝门窗监理交底卫生间技术交底喷播草籽技术交底钢结构雨棚安全交底 工作。按图纸范围确定施工范围,标出外框范围线,清出障碍物。联系施工需用材料、机械的进场工作。根据业主提供的平面控制坐标点与水准控制点进行引测。根据施工图规定的道路工程坐标点,进行测量放样的业内复合计算。 3.3定位放线 根据现场实际情况,在道路两侧沿线间隔50m左右布置测量控制桩,轴线定位(坐标)桩与高程测量控制桩合用。控制点沿道路中心线两侧交错间隔布置,形成多个控制体系,同时控制桩做醒目标志,以防在施工过程中被碰动。土方施工后,测量人员应及时重新放线,路基处理后,应在路基上测定路面中心线、边界线以及标高控制点。 其基本步骤为:校验路基轴线控制桩;合格后,根据轴线控制桩详细放出路边线以及设置标高控制桩。 放线自检和业主监理验收后方可使用。验线允许偏差根据规范规定。 3.4 土方开挖 施工方法:在施工测量放线确定基础位置,经检查复核无误后,作为施工控制的依据,并经过监理确认后,即可进行基础土石方的开挖。 主要施工机具:挖掘机、装载机、尖、平头铁锹等。 3.4.1作业条件: 土方开挖前,应摸清地下管线等障碍物,以及地下水位等情况,并应将施工区域内的地下障碍物清除和处理完毕。 道路的定位控制线(桩),标准水平桩及基槽的灰线尺寸,必须经过共同检验合格,并办完预检手续。考虑在机械无法作业的部位和修整边坡坡度采用人工进行施工。熟悉图纸,做好技术交底。索取地勘资料及 气象资料。 夜间施工时,应合理安排工序,防止错挖或超挖。施工场地应根据需要安装照明设施,在危险地段应设置明显标志。 3.4.2挖土方流程: 确定开挖的顺序和坡度?沿灰线切出槽边轮廓线?分层开挖?修整槽边?清底。 (1)基地坡度剖面图: 现场土质为粉质粘土,开挖 深度不超过1.5m可不放坡,不加支撑,挖深度超过1.5m必须放坡,放坡坡度为1:0.75。 (2)开挖基槽: 采用反铲挖土机开挖基槽从槽的端头,以倒退行驶的方法进行开挖,将土方甩到基槽两侧,应保证边坡的稳定。场地以下耕织土层直接清理现场,剩余好土回填基槽使用。 (3)施工要求: 基坑(槽)开挖后,不得直接开挖至设计底标高,避免机械开挖扰动地基土层。在挖到距槽底20cm以内时,测量放线人员应配合抄出距槽底20cm水平线,并在槽壁上每隔3~5m钉水平标高小木桩或短钢筋,在挖至接近槽底标高时0.2m时,用尺或事先量好的20cm标准尺杆,随时以小木桩校核槽底标高。最后由两端轴线(中心线)引桩拉通线,检查距槽边尺寸,确定槽宽标准,据此修整基槽,最后人工清除槽底土方。 土方开挖时应注意边坡稳定。严禁切割坡脚,以防导致边坡失稳,当边坡坡度陡于五分之一,或在软土地段,不得在挖土上侧堆土。必要时可适当放缓边坡或设置支撑。施工时,应加强对边坡、支撑、土堤等的检查。同时应注意基坑边沿控制线好其他单位设施,避免损伤. 夜间施工时,应有足够的照明设备,在危险地段应设置明显标志,并要合理安排开挖顺序,防止错挖、超挖。 雨期施工在开挖基坑(槽)时,应注意边坡稳定,必要时可适当放缓边坡坡度,防止地面水流入。坚持对边坡进行检查,发现问题要及时处理。 (4)应注意控制的质量问题 基础底部土方超深开挖:开挖基坑(槽)或管沟均不得超过基底标高。如个别地方超挖时,其解决方法应取得设计单位的同意,不得私自处理.基坑开挖中如遇局部地基问题,施工方应及时通知有关各方人员现场共同协商处理,未得到各方任何之前,不得擅自处理。基坑开挖并清理完,经钎探(根据当地监理、质检部门要求)和验槽合格后,方可进行下道工序的施工。 基底未能得到保护:基坑(槽)开挖后应尽量减少对基础底部基土的扰动。如基础不能及时施工时,可在基底标高以上留出0.3m厚土层,待做基础时再挖掉。开挖尺寸不足:基坑(槽)或管沟底部的开挖宽度,除结构宽度外,应根据施工需要增加工作面宽度。如排水设施、支撑结构所需的宽度,在开挖前均应考虑。基坑(槽)边坡不直不平,基底不平:应加强检查,随挖随修,并要认真验收。 3.5卵石路基基层施工 路基施工是道路施工重点, 必须将原地面上各种杂物清除,保证填土表面无积水。 对于压路机不能压到得地方,采用夯机夯实或者人工夯实。 厂区道路路基密实度不小于96%,经检测合格后方可经行后续施工。 本工程采用200厚卵石基层,基层每边比基础宽出270mm。自卸汽车倒至基槽漂石,反铲挖掘机整平后,压路机压实。 3.5.1材料 卵石:采用粒径100-200mm卵石做为底基层。上层为天然砂砾,水 泥稳定砂砾层及粗,中式沥青面层。 3.5.2施工方法 (1)施工测量 施工前对下承层按质量验收标准进行验收之后,恢复中线,直线段每20m设一桩,并在两侧路面边缘0.3-0.5m处设标志桩,在标志桩上用记号笔标出漂石基层边缘设计标高。 (2)整平 卵石入槽后,挖掘机倒退法整平。进行分层施工,基层的设计厚度为200mm,根据现场实际情况,基底土方含水率较大,为了保证第一层漂石整体均匀性, 防止地基翻浆,第一层漂石虚铺厚度400mm,碾压整平后,直接回填天然砂砾,分层碾压至设计标高。 (3)试验取样 选择资质符合要求的试验室进行戈壁分层碾压取样试验。现场取样每层天然砂砾碾压完成后,由监理单位见证试验室现场对戈壁取样,压实系数要求不小于0.96.取样要求,每1000平方取样两点,不足1000平方时按两点取样。 3.6天然砂砾路基施工 天然砂砾应平铺整平后,进行机械碾压。压路机采用18t内震式。碾压时先轻后重,先慢后快。直线段,由两侧路肩向路中心碾压,平曲线段由内侧向外侧进行碾压。碾压时,主碾重叠不小于30cm。 压路机的碾压速度,头两遍采用1.5-1.7Km/h,以后采2.0-2.5Km/h。在规定的时间内碾压到要求的压实度,达到没有明显的轮迹。碾压过程中,如有“弹簧”、松散、起皮等现象,铲除换填,使其达到质量要求。分段施工时,上下两层接缝距离为500mm,接缝处夯压密实。 3.7高强聚酯土工格楞 土工格栅选取用聚酯涤纶纤维为原料。采用经编定向结构,织物中的经纬向纱线相互间无弯曲状态,交叉点用高强纤维长丝捆绑结合起来,形成牢固的结合点,充分发挥其力学性能,高强聚酯土工格栅具有抗拉强度高,延伸力小,抗撕力强度大,纵横强度差异小,耐紫外线老化、耐磨损、耐腐蚀、质轻、与土或碎石嵌锁力强,对增强土体抗剪及补强提高土体的整体性与荷载力,具有显著作用。 土工格栅施工要点: 1、施工场地:要求压实平整、呈水平状、清除尖刺突起物。 2、格栅铺设:在平整压实的场地上,安装铺设的格栅其主要受力方向(纵向)应垂直于路堤轴线方向,铺设要平整,无皱折,尽量张紧。用插钉及土石压重固定,铺设的格栅主要受力方向最好是通长无接头,幅与幅之间的连接可以人工绑扎搭接,搭接宽度不小于10cm。如设置的格栅在两层以上,层与层之间应错缝。大面积铺设后,要整体调整其平直度。当填盖一层土后,未碾压前,应再次用人工或机具张紧格栅,力度要均匀,使格栅在土中为绷直受力状态。 3、填料的摊铺和压实:当格栅铺设定位后,应及时填土覆盖,裸露时间不得超时48小是,亦可采取边铺设边回填的流水作业法。先在两端摊铺填料,将格栅固定,再向中部推进。碾压的顺序是先两侧后中间。碾压时压轮不能直接与筋材接触,未压实的加筋体一般不允许车辆在上面行驶,以免筋材错位。分层压实度为20-30cm。压实度必须达到设计要求,这也是加筋土工程的成败关键。 4、防排水措施:在加筋土工程中,一定要作好墙体内外的排水处理;要做好护脚,防冲刷;在土体内要设置滤、排水措施。 3.8水泥稳定砂砾基层施工 1.摊铺混合料前,要清扫砂砾执层,垫层上不能有杂物。要严格检 查底基层之纵断高程和横断面坡度,检测指标与偏差必须满足设计与规范要求。然后洒水湿润底基层表面,但不能有自由水存积。 2(用摊铺机摊铺混合料时,中间不宜中断。 因故断超过初凝时间过长,应设置施工缝。 摊铺机行下速度控制在1M-5M/min,并匀速行进。 3.水泥稳定砂砾基层施工中,横缝是不可避免的,对接缝处理规范有严格要求。另外根据实际操作之经验,我处理之方法是先在横缝处多填混合料,压路机横向碾压2-3遍,再铲除明显高出之部分,再横压力1-2遍,最后再纵向依次碾压,压路机纵向行驶要超过横缝,碾压完毕再人工挖除1米,以便下次接缝。 4.水泥稳定砂砾基层碾压成型后,要能时喷雾洒水,以防止水泥稳定基层风干。48小时内要保持表面湿润不干燥,然后连续约3天,以后可适当减少洒水次数,但必须保持表面湿润。洒水养生不少于7天,期间要禁止一切车辆通行,洒水车要缓慢行进洒水均匀。流水施工作业时,水泥稳定砂砾基层洒水养生4天后,可洒透乳化沥青养生,第5天可铺沥表下面层。这样作业对基层质量没有影响,还可快加工程进度。 3.9路缘石施工 路缘石施工应符合下列要求: 核对道路中心线无误后,进行边线放样,确定路缘石底面标高。 路缘石施工应根据路缘石平面位置和顶面标高,放样依次排砌。相邻侧石接缝必须平齐,然后进行勾缝。 3.10玻纤土工格栅施工 常用的玻纤土工格栅有带自粘胶和不带自粘胶两种,带自粘胶的可直接在已平整的基层铺设,不带自粘胶的,通常采用钉子固定法。 钉子固定法所需材料为: i. 40×40×0.3毫米的固定铁皮,要求平整不翘角 ii. 2英寸钢钉(优质水泥钉) 1、钉子固定法铺设玻纤土工格栅时,先将一端用固定铁皮和钉子固定在已洒布粘层沥青的下层结构上,钉子可用锤击或射钉枪射入,再将格栅纵向拉紧并分段固定,每段长度为2-5米,对于水泥混凝土路面,可按收缩缝间距分段。钢钉位置设于接缝处,要求格栅拉紧时,其纵横向均处于挺直张紧状态。 2、 格栅搭接距离为:纵向接头搭接距离不小于20厘米,横向搭接距离不小于15厘米,纵向搭接应根据沥青摊铺方向,将前一幅处于后一幅之上。 3、不能将钉子钉于玻纤格栅上,也不能用锤子直接敲击玻纤格栅,固定好后,如发现钉子断裂或铁皮松动,则需重新固定。 4、玻纤格栅铺设固定完毕后,须用胶辊压路机适度碾压稳定。使格栅与原路表面粘牢固,严格控制运送混合料的车辆出入,在格栅层上禁止车辆急转向、急刹车和倾泻混合料脚料,以防止对玻纤格栅的施工损伤。 5、施工注意事项 (1)严格控制远送混合材料的车辆出入,在格栅层上禁止车辆急转向、急刹车和倾斜混合材料,以防止对玻纤格栅的损坏。 (2)玻纤格栅背胶易溶于水,雨天或路面潮湿时不得施工。 (3)玻纤格栅为玻璃纤维制造,对人体皮肤易产生刺激作用,施工人员须戴防护手套。 (4)当使用胶轮压路机需注水增加重量时,其注水量不能太慢,以防溢流到玻纤格栅上,造成其背腹失去粘性。 (5)玻纤格栅铺设过程中,若发现原有较小的坑塘没有预先填平,可在铺好的格栅上将对应坑塘的部分剪去,以便在铺上层沥青混合材料时能完全填平坑塘。 (6)格栅铺设时,要求路面温度在5?—6? (1)机械铺设 将整卷土工格栅装在拖拉机前的放卷架上,注意其粘性面向下。 使拖拉机向前走,保证土工格栅平直地粘在路面上。s 用胶轮的轻型压路机碾压1-2遍。 摊铺沥青混合料路面。 (2)人工铺设 将整卷土工格栅放在卡车后或手推车的放卷架上,注意其粘性面向下。确保放卷轴已锁定,布卷不致自由松动。当卡车(或手推车)慢慢向前走时,应踩住格栅一端。如格栅有松驰时,即时调整以防皱折。 用胶轮的轻型压路机碾压1-2遍,激活格栅背胶即可摊铺沥青路面。 3.11沥青混凝土面层施工 (1)沥青透层油 沥青透层油在已建成的石灰粉煤灰砂烁上洒布,主要材料为慢烈的洒布型阳离子或阴离子乳化沥青(PC-2或PA-2)及粒径为0.5-1.0cm的石屑。透层沥青采用沥青洒布车喷洒,用量1.0L/?,洒布要求均匀, 不产生滑移和流畅。当有遗漏时,采用人工补洒。浇洒透层沥青后,易立即洒石屑或粗砂,用量3m?,1000?.然后用6-8T的钢简式压路机展压一边。洒布之后,保证24小时内不得扰动,使沥青充分渗透到基层中。 (2)沥青混合料面层施工工艺: ?、准备工作: 沥青混凝土路面使用二台摊铺机,两侧为基准线,两机相距10m左右。先对沥青混凝土面层的施工将切实做好基层验收、技术准备、人员组织、设备组织、作业准备、混合料运输、混合材料摊铺和碾压底基验收这八个环节。基层和沥青混凝土面层平整度、厚度必须严格满足设计要求,为上面层施工打下良好基础。 a、材料准备:施工使用的沥青混合材料必须按照要求申报使用许可,如改变已批准的混合料配比,则需重新申报。 b、人员准备:摊铺实验之前,在驻地监理办和现场指挥在场的情况下汇报施工方案并召开技术交底会,明确各岗位的职责和技术要求,做到分工明确、各司其职、井然有序并在驻地办批准下进行施工。试验段后,召开技术总结会,针对存在的问题和不足,制定有效的整改措施进一步完善施工工艺并经监理工程师批准后进行全面施工。现场指挥和整体工作协调;现场疏导、安全及车辆调配;现场施工、跟机作业及准备工作;看护基准线设备、调控宽度和油边调控摊铺石的高程、厚度和横坡度;测量温度、组织碾压及试验检测等工作将配备专人负责。 c、机器准备:参加沥青混凝土面层施工的机器设备必须处于完好状态,备份施工机器及水车,加油车和装载机等辅助机器与施工密切配合,做到随叫随到。各种作业机器严禁有漏油现象,维护和保养机器时,必须采取有效措施防止污染和破坏。沥青混凝土面层施工时,将使用作业机具如下表: 机器名称 型号 数量 用途 摊铺机 ABG423 2台 摊铺 钢轮压路机 DD110 2台 初压 钢轮压路机 DD130 2台 复压、终压 水车 5T 1台 加水 其他 少火车、烙铁、平粑、筛子、方掀、靠尺、手推车 d、检测仪器准备:检测仪器配备主要有直尺、红外线测温计、平整仪等。在施工作业前做全面检查,并经调试证明处于性能良好状态。 e、确定作业面:作业准备在施工沥青混凝土面层前先确定好其作业面,以使施工能连续进行,并组织人员: 熟悉作业面高程,纵横坡、超高、加宽等技术参数。 了解基层施工中的问题,并确定相应的补救措施。 标划施工大样线,对调控点、变坡点等特殊点和摊铺机的行车线与分车线都必须有明显标识。 施工前由施工技术人员依据道路5米一个横断面在两侧做出标记,并注明相应桩号。 随后在两侧平台上将基准线固定,安装完毕后,设专人看护。首先对下承层进行全面自检,按照规范要求对密实度、平整度、高度、厚度、横坡、纵坡等进行全面检测,自检合格后报验验收,同时设点作为以后路面各层检测的固定点位。 验收通过后,进行下一步工序。 ?、沥青混合料生产、运输和卸料监督: 沥青混凝土的生产和运输首先由我项目部委托试验室控制沥青的生产质量,按规范要求完成各种室内试验,并及时将结果向监理人员反馈未经监理人员同意不能调整配合比,严禁手动放料。专人负责测量温 和观看外观质量,以避免不合格材料用于施工中。其次,热拌沥青混合料采用较大吨位的汽车运输(料厂提供)、车厢清扫干净,为防止沥青与车厢板粘结,可涂一层油水混合液,但车厢底部不得有余液积聚。并且根据沥青混凝土拌和设备的生产能力合理安排运输力量,考虑到尽力可能使摊铺机前方运料车在等侯卸料的保证在5辆车以上。在连续摊铺过程中,运料车在摊铺机前10-3-cm处停住,不得撞击摊铺机。卸料过程中运料车挂空挡,靠摊铺机推动前进。运料车用篷布覆盖,用以保温、防雨雪、防污染。沥青混合料运至摊铺地点后,委派专人逐车检查拌合质量及油温。凡温度低于规定要求(140-160、东施170-160)及严重离席料、花料、油大料或已经结成团块、以遭雨淋湿的混合料立即清除,不摊铺在道路上。 ?、摊铺 摊铺机就位时,在熨平板下面铺放垫木,垫木的顶面高即为该点的设计高程加摊层,垫木的实测高程准确,并反复校准,直至满足规范要求后,摊铺机方可就位。摊铺机在收料前在料斗内涂刷少量防止粘料用的柴油。摊铺机在运行前事先预热,起步后立即检测高程、横坡和厚度,及时进行校对与调整,此项工作在摊铺30米距离内完成,如有必要可停机检测,问题较大时必须重新起步。沥青混合料的松铺系数根据实际的混合料类型,施工机器和施工工艺等,由试铺试压方法或根据规范中松浦系数的规定选用。沥青混合料的摊铺温度符合规范要求,并根据沥青标号、粘度、气温、摊铺层厚度选用。沥青混合料必须缓慢、均匀、连续不间断地摊铺。摊铺过程中不得随意变换速度或中途停顿。摊铺速度根据拌和机产量、施工机器配套情况及摊铺层厚度、宽度情况定,并符合2-6m/min的要求。再摊铺过程中,摊铺机螺旋并料器不停顿的转动,两侧保持有少于送料器高度2/3的混合料,并保证在摊铺机全宽度断面 上不发生离析。对于局部小离析处筛细料处理。熨平板按所需厚度固定后,不得随意调整。 在摊铺过程中有专人指挥车辆卸料,衔接及时,从儿减少摊铺机运行中停机待料。如果出现供料段档,停机并适当压车,严禁随来料随摊铺。在摊铺过程中,我单位设专人及时跟踪测量沥青路面的纵段面高度,横坡及摊铺厚度,如不符合要求及时调整。用机器摊铺的混合料,尽量不用人工反复修整。 当出现横断面不符合要求、构造物接头部位缺料、摊铺带边缘局部缺料、表面明显不平整、局部混合料明显离析、摊铺机后有明显的托痕等情况时,可用人工作局部找补或更换混合料,并且现场主管人员指导下进行。缺陷严重时,予以铲除,并调整摊铺机或改进摊铺工艺。当属机器原因引起严重缺陷时,立即停止摊铺。人工修补时,工人不宜站在热混合料层面上操作。当机下料温过低时,必须抬机做横缝。对未经初压的摊铺料禁止随意踩踏和修整。 ?、碾压: 沥青混凝土料的压实,根据不同的料温按初压、复压、终压(包括成型)三个阶段进行。设专人检测沥青混合料温度和指挥碾压机器,摊铺后沥青混合料温度在初压阶段,路边插红色旗作为标志。 沥青混合料的温度在复压阶段,在路边插黄色旗作为标志。沥青混合料温度在终压阶段,在路边插绿色旗作为标志。 沥青混合料施工温度一览表 沥青混合料类型 普通沥青混合料 出厂温度 ? 140-160(冬施170-160) 到场温度 ? 130-150(冬施-150) 摊铺温度 ? 120-150(冬施160-130) 碾压温度 ? 120-170 (冬施130-90) a、初压在混合料摊铺后较高温度进行,低速前进不得产生推移、发裂,我单位将采用1台DD110双钢轮压路机进行作业(1.5-2.0km/h)。压路机由低向高碾压。相邻碾压带重叠1/3-1/2轮宽,压完全幅为一遍。边缘无知当时,用靶子将边缘的混合材料稍稍靶高,然后将压路机得外侧轮伸出边缘10cm以上碾压。也可在边缘先空出度30-40cm,待压完第一遍后,将压路机大部分重量位于以压实过的混合料面上再压边缘,以减少向外推移。压路机碾压2遍(先静后振),其压力不宜小于350N/cm。 初压后检查平整度、路拱,必要时予以适当休整。碾压时将驱动轮面向摊铺机,碾压路线及碾压方向禁止突然改变而导致混合料产生推移。压路机启动、停止必须减速进行。在此过程中,特别注意平整度和路拱。 b、复压:复压紧接在初压后进行,并符合下列要求:复压采用DD130震动压路机(4-6km/h),碾压遍数经试压确定,不宜少于4-6遍,达到要求的压实度,并无显著轮迹。当采用振动压路机时,震动频率宜为35-50HZ,并根据混合料种类、温度和厚度选用。层厚较厚时选用较大的频率和振幅,相邻碾压带重叠宽度为10-20cm。振动压路机倒车时先停止振动,并在向另一方向运动后再开始震动,以避免混合料形成鼓包。振动压路机碾压两遍,胶轮压路机碾压两遍。 c、终压:终压紧接在复压后进行。终压选用1台DD130压路机(3km/h)静碾,且不得少于两遍,并无轮迹。路面压实成型的终了温度符合规范的要求。终压时,由质控人员用平整度仪检测平整度,核子密度仪测密度。如不满足要求,及时赶压。 机器碾压速度一览表 压路机类型 初压 复压 终压 钢轮压路机 1.5-2.0km/h 3.0km/h 3.0km/h 振动钢轮 不振1.5-2.0km/h 振动4-6km/h 不振2-3km/h 压路机的碾压段长度以与摊铺速度平衡为原则选定,并保持大体稳定。 压路机每次由两端折回的位置阶梯形的随摊铺机向前推进,使折回处不在同一横断面上。压路机不得在未经压实的混合材料上进行倒轴,必须沿同一轮迹反回,在摊铺机连续摊铺的过程中,压路机不得随意停顿。设专人清洁压路机轮。压路机不得在未碾压成型并冷却的路段上转向、掉头或停车等候。振动压路机在已成型的路面上行驶时关闭振动。对压路机无法压实的构造物接头、拐弯死角、加宽部分及某些路边缘等局部地区,采用振动劣板压实。对边缘处使用人工夯锤、热烙铁补充压实。碾压结束后,在未冷却前,压路机或其他车辆不得在路上停放,不得散落矿料、油料等杂物,并及时检测平整度和压实度。 摊铺过程中如遇大雨,必须立即停止摊铺,并覆盖运输车辆和摊铺机内混合料,对以摊铺的料层,适当提高碾速,采用振动方式尽快结束碾压。对已碾压完毕的段落,24小时后放行交通。 d、接缝:在施工缝及构造物两端的连接处必须仔细操作,保证紧密、平顺。在纵缝上的混合料,在摊铺机得后面立即用DD130钢轮压路机以静力进行碾压,碾压工作连续进行,直至接缝平顺而密实。摊铺时采用梯队作业的纵缝采用直渐热接法。由于工作中断,摊铺材料末端已经冷却,或者在第二天恢复工作时,就做成一道横缝。且在相连层次与相邻程间错开1米。 具体操作方法如下:在施工结束时,摊铺机在接近端部前约1米处将熨平板稍稍抬起势力现场,用人工将端部混合料铲齐后再予碾压。然后用3米直尺检查平整度,趁尚未冷透时垂直创除端部层厚不足部分,使下次施工时成指教连接。在新剖齐的直茬垂直面上喷一薄层粘层油,并用喷灯火焰热原沿缝往复均匀考热。 横向接缝的碾压先用DD130压路机进行横向碾压。碾压时压路机位于已压实的混合料层上,深入新铺层的宽度为15cm。然后每压一遍向新铺混合料移动15-20cm,直至全部在新铺层上为止,再改为丛向碾压。当相邻摊铺层已经成型,同时又有丛缝时,可先用钢筒试压路机沿纵缝碾压一遍,其碾压宽度为15-20cm,然后再沿横缝作横向碾压,最后进行正常的纵向碾压。 不在同日摊铺的纵缝,在摊铺新料前对先铺带边缘加细修理,将松动、裂纹、厚度不足或为充分压实部分清除掉,刨齐缝边垂直,线形直顺,并喷刷一薄层粘层油,热沥青方可摊铺新料。用热混合料敖于已刨之纵缝上,一般宽15-20cm,高约10-15cm,超前10-20cm于摊铺点。纵缝在摊铺后立即碾压,碾压时碾轮大部分压在以碾压路面上,约10-15cm宽度压在新沥青混合料上,然后逐渐移动(侧轴)越过纵缝。横向施工缝摊铺机摊铺混合料,因故中断时,必须设置横向接缝。摊铺机驶离混合材料末端,人工将末端混合材料弄整齐,紧靠混合料放两根方木,方木高度与混合料的压实厚度相同。整平紧靠方木的混合料;放牧的另一侧用砂烁或碎石回填约3米长,其高度应高出方木几厘米;将混合料碾压密实,在重新开始摊铺混合料之前,将砂烁或碎石和方木除去,并将下承层顶面清扫干净和拉毛;摊铺机返回到已压实层得末端,重新开始摊铺混合料;如压实度末端未用方木作支撑处理,则将摊铺机附近及其下面未经压实的混合料铲除,并将以碾压密实且高程和平整度符合要求的末端挖成一横向(与路中心垂直)垂直向下的断面。然后在摊铺新的混合料。 半幅施工中,纵缝必须垂直相接:在前一幅摊铺时,在靠后一幅的一侧用方木作支撑,其高度与混合料层的压实厚度相同。养生结束后,在摊铺另一幅之前,拆除支撑木。在混合料摊铺整型、稳定、找平修整、 压实过程中完全中断交通。碾压完毕后,外观上达到表面平整密实。对于多层结构层施工,上下横缝间距不下于1m,纵缝间距不小于30cm。 e、取样、试验和检验: 对使用同种料源的沥青混合料每天取样一次,并按照规范的标准方法对规定的项目进行检验。 混合料施工过程中,每天或2000m2取样一次,进行含水量、石灰含量、无侧限抗压强度等的试验。在已完成的摊铺层上根据本工程技术规范要求的频率进行压实度的试验。 试验段设置8个测点,每碾压4、6、8遍时测高(以及碾压前松浦标高),以得出实际松浦系数,直至最后土层表面不再下降为止。密实度分别在4遍、6遍、8遍时分8个点个检测一遍,用以控制碾压遍数。试验段结束后,将资料汇总上报监理工程师。 f、开放交通及冬季施工措施:沥青混合料路面待摊铺层完全自然冷却,混合料表面温度低于50?后,并在24小时后,再根据实际情况开放交通。需要提早开放交通时,可洒水冷却降低混合料温度。 沥青路面雨季施工符合下列要求: 1、注意天气预报,将强工地现场与沥青拌合场联系,缩短施工长度,各项工序紧密衔接; 2、运料汽车和工地有防水设施,并做好基层和路肩的排水设施; 3、当遇水合下层潮湿时,不得摊铺沥青混合料,对未经即遭雨淋的沥青混合料,全部清除,更换新的。 沥青路面冬季施工要求: 1、冬施期间应提高沥青混合料拌合温度,石油沥青混合料为160-170?;摊铺时间宜在上午9h至下午4h进行;施工气温低于5?,不宜摊铺热拌沥青混合料;快速路、主干路施工气温不宜低于10?。 2、运输沥青混合材料应采取保温措施,石油沥青混合料到达工地温度不得低于150?。 3、基层表面应干燥、清洁,无冰、雪、霜等。并应准备哈奥挡风、加热、保温工具和设备等。 4、接茬处预热温度宜保持在65-70?,碾压中,应用压路机器茬加强碾压两遍以上。 5、人工摊铺,卸料后应及时覆盖保温;并宜采用‘三块二及时’操作法,即:卸料快、摊铺快、楼平快,及时修整、及时碾压。 6、冬季期间应备有足够的压路机等进行碾压。碾压温度不应低于90?。 g、养生:压实成型合格后,油面温度降至与大气温度同时即可开放交通。 (3)、质量要求 a、主控项目 1、沥青混凝土路面压实度应符合6.2.1的规定。 2、沥青混凝土路面厚度符合设计要求和表6.2.1的规定。 3、沥青混凝土路面的弯沉值应符合设计要求。 沥青混凝土路面主控项目充许偏差表 序号 项目 规定值或充许偏差 检验频率 检验方法 1、压实度 快速路、主干路?96% 1000m2 1 见附录B 次干路、支路?95.6% 2、厚度 -5mm----+10mm 1000m2 1 用钢尺量 3、弯沉值 符合设计要求 20m 路宽(m),9 1见附录F9—15 2 ,15 3 注:?用蜡封法或表干法测得的现场沥青混凝土密度与用马歇尔稳定度仪试验或30Mpa压力成型法则得的标准密度相比较; ?本表中压实度采用马歇尔稳定度仪击实成型标准。 ?弯沉值单位1/100mm; ?本表第2、3项也可采用自动检测设备进行检测; ?改性沥青混凝土路面可参照此表进行经验。 b、一般项目 1、表面应平整、坚实,不得有脱落、掉渣、裂缝、推挤、烂边、粗细料集中、油斑等现象。 2、用12t以上压路机碾压后,不得有明显轮迹。 3、施工接缝应紧密、平顺,烫缝不应估焦。 4、面层与路缘石、平石及其它构筑物应接顺,不得污染其他构筑物,不得有积水现象。 5、沥青混凝土路面质量充许偏差见表 沥青混凝土路面变差表 序号 项目 规定值或充许偏差 检验频率 检验方法 1抗滑 摩擦系数 符合设计要求 200m 1 摆式仪 见附录H 全线连接 横向力系数车 构造深度 符合设计要求 200m 1 砂铺法 2 平整度 快速路、主干路σ?1.2mm 100m 路宽(m),9 1用测平仪检测见附录G,见注? 9---15 2 次干路、支路σ?9 1用3m直尺和塞尺连续量取两尺最大值见注? 9-15 2 ,15 3 3 宽度 不小于设计值40m 1 测距仪或用钢尺量 4 中线高程?10mm 20m1 用水准仪测量 5 中线线位20mm 200m4用经纬仪测量 6 横断高程?10mm且横坡差不大于3%20m路宽(m),9 2 用水准 仪测量 9—15 4 , 15 6 7 井框与路面高差?5mm 每座4 十字法用塞尺最大值 注:?测平仪为全线每车道连续监测每100m计算标差σ;无测平仪时即可采用3m直尺检测;表中检验频率点数为测线数; ?本表第1、2项也可以采用自动设备进行检测; ?底基层表面应按设计规定用量撒泼透油层、粘层油; ?改性沥青混凝土路面可采用此表进行检验。 3.12降水施工 由总包单位提供的地勘报告中说明该场地的地下水为空隙渗水, 埋深在1,2.5m。经观察坑槽开挖情况,渗水速度极慢,再考虑自然 降水,施工中对于道路开挖的沟槽采取分段挖开及时回填,明沟降排 即可满足要求,在每隔50m设置一个集水坑,用50m扬程污水泵将集水 坑内的水直接排入厂区北侧河内。 4、质量控制措施 4、1)质量保证体系及职责 , 根据工程项目的具体情况,设置本项目施工队的质量保证体系图7-1;明确各职能人员和项目施工队的主要工作职能,并且与其相关的质量程序文件挂钩,各负其责。下属各班组数量及其任务分配,应根据实际情况确定,并在施工过程中予以必要、及时的调整。 项目队长 质量员 技 材计 术 料划 员 员 员 施工队及作业人员 新彊大全新能源5000吨/年多晶硅片项目土建工程施工队质量保证体系 4(2)质量标准 4(2.1保证项目 1)基底的土质必须符合设计要求。 2)天然砂砾的干士质量密度必须符合设计要求和施工规范的规定。 4、2(2基本项目 1)面路标高均匀,分层虚铺厚度符合规定,夯压密实,表面无松散,翘皮。 2)留槎和接槎,分层留槎的位置、方法正确,接槎密实、平整。 3)天然砂砾地基允许偏差项目表1-319 项 项目 允许偏差(mm) 检验方法 次 1 顶面标高 用水平仪或拉线和尺量检查 ?25 2 表面平整度 25 用2m靠尺或楔形塞尺检查 5. 冬、雨季施工安排 一、冬期施工概念 根据当地多年气象资料统计,,当室外平均气温连续5天稳定低于 5?即进入冬期施工,当室外平均气温连续5d高于5?时解除各期施工。 二、冬期施工特点 1、冬期施工由于施工条件及环境不利,是各种安全事故多发季节。 2、隐蔽性、滞后性。即工程是冬天干的,在春天开始才暴漏出来问题,因而给事故处理带来很大难度,不仅给工程带来损失而且影响工程使用寿面。 3、冬期施工的 计划 项目进度计划表范例计划下载计划下载计划下载课程教学计划下载 和准备工作时间性强,这是由于准备工作时间段,技术要求高。 三、冬期施工基本要求 1、冬期施工前两个月即应进行冬期施工战略性安排; 2、冬期施工前一个月即应编制好冬期施工技术措施; 3、冬期施工前一个月做好冬期施工材料、专用设备等施工准备工作; 4、搞好相关人员培训和技术交底工作。 四、冬期施工的准备 1、编制冬期施工的准备,冬期施工组织设计,应包括下列内容:确定冬期施工的方法,工程进度计划、技术供应计划、施工劳动力供应计划、能源供应计划、防火安全措施、劳动用品、冬期施工安全措施;冬期施工各项安全技术经济指标和节能措施。 2、组织好冬期施工安全教育培训 项目部根据冬期施工特点,调整好机构和人员,并制定好岗位责任制,加强安全生产管理。主要加强保温、测温、冬期施工技术机构、能源管理等机构,并从实相应的人员。安排气象预报人员,了解近期、中期天气、防止寒流突袭。对测温人员、保温人员、能员工、管理人员组织专门的技术业务培训、学习相关知识、明确岗位责任制、经考 核合格方可上岗。 3、 物资准备 物资准备内容如下:外加剂、保温材料、温度标计及工器具及劳动用品现场管理和技术管理的表格、记录本、燃料及防冻油料等。 4、 施工现场的准备 ?场地要在土方冻结前平整完工、道路应畅通、并有防止路面结冰的具体措施; ?项目部组织有关机具、外加剂、保温材料(草包、木工部、薄膜)等实物进场; ?生产上水系统应采取防冻措施、并设专人管理、生产排水系统应畅通; ?按照规划落实职工宿舍、办公室等临时设施取暖措施。 五、沥青冬季施工措施 冬季对沥青混凝土面层施工影响较大。一般情况下,当气温低于0度时,不再进行沥青混凝土面层的施工。冬季沥青混凝土施工时可对在中午阳光从充足的时候进行。施工前,应及时联系拌合场联系迅速将沥青混合料运至施工现场,运输过程中要采取保温措施,同时要求混合料出厂温度升高10度,沥青混合料面层铺筑碾压完成应待4-6小时后开放交通。 六、冬季砼施工措施 1、拌合时加温拌合用水,砂石料中剔除冰块,霜块和冻结的砂团; 2、适量减小水灰比,增加砼胶棒时间,砼配合比掺入防冻液,以防砼受冻; 3、要缩短成活工序间隙,并在模板边预设测温孔,随时测定内温; 4、准备好足够的覆盖物,浇捣完成时及时覆盖,尤基冬季在挡风面更加更加应覆盖严密,包括模板外侧需用草包、土木布覆盖好保温; 5、砼表面应及时清扫积雪,防止积雪冻融时吸收砼中热量而使砼产生脱皮现象; 6、及时和气象站联系,遇特大寒流应停止浇捣若在浇捣好后遇特大寒流侵袭,则应采取燃料加温,蒸汽养护等特殊措施。 七、冬期施工安全措施 1、人工破碎冻土应当注意的安全事项; ?注意去掉头打出的飞刺,以免飞出伤人 ?掌铁 的人与掌锤的人,不能脸对脸,应当互成90?。 2、脚手架、马道要有防滑措施,及时清理积雪、外脚手架要经常检查加固; 3、大雪、轨道电缆结冰和6级以上大风等恶劣天气、应当停止垂直运输作业,并将掉笼降到地面,切断电源; 4、风雪过后作业,应当检查安全保险装置并先试吊,确认无异常方可作业; 5、吊机路轨不得铺设在冻胀性土层上,防止土壤冻胀或春季融化,造成路基起伏不平,影响吊机的使用,甚至发生安全事故; 八、冬期施工防火要求 1、施工现场临时用火,要建立用火证制度由工地安全负责人审核。用火证当日有效,用后收回。 2、使用可燃材料进行保温的工程,必须设专人进行监护,巡逻检查。 3、保温材料定位后,禁止一切用火、用电作业,特别是禁止下层进行保温作业,上层进行用火,用电作业。照明线路、照明灯具应该远离可燃的保温材料。道路的施工在雨季,合理的安排雨季施工,是整 个工程质量的一项重要工作。根据本工程的施工内容,施工环境及施工特点,确定以下雨季施工措施: 在不影响总进度的前提下,尽量避开雨天。施工中遇上下雨时,采取分段分期完成,组织力量,集中突击。摊铺一段,施工一段,循环推进,防止路基槽受暴雨冲刷。 路基施工,注意排水工作。雨季修筑土基路,应做到随挖随运,随铺填随压实。雨前和收工前将铺填松土压实完毕,不致积水。 路基施工雨天排水措施:同时在槽外两侧开挖水沟防止地面水流入槽内。 下雨天不得进行土方回填工作。 合理安排好材料进场计划,不一次性在现场大量储备回填用料。灰料进场及时摊铺,以防遇水固化,造成材料浪费。 6. 安全技术措施 坚持预防为主,安全第一的方针,重视和加强安全施工管理工作,保障施工人员的人身生命安全。 贯彻落实国家、地方、行业、总包单位、业主有关安全、卫生的政策、法规、标准和各项规章制度。 严格执行总包单位、业主现场职业健康安全与环境管理规定。 执行公司安全和环境管理第三层管理文件。 建立健全现场安全生产管理责任制、分工明确、责任到人、设立专职安全员。 执行安全检查制度,分级定期进行安全检查。实行安全教育制度,提高职工安全意识。 施工人员进入现场之前必须进行安全教育,必须戴好安全帽及个人防护用品。 土方开挖、回填、路基夯实碾压时派专人指挥施工机械,并在周边设置警示围护。人机配合施工时注意保持安全距离。 施工中使用的电动工具,要专人专用。各种电动机械设备,必须有有效的接地和防护措施。现场用电必有漏电开关,机具做到一机一闸。夯机操作人员必须戴绝缘手套。 夜间施工时,必须保证有足够的照明。 现场作业人员必须服从指挥,严禁离岗、脱岗。 所有机械电机在雨天必须盖上防潮布,防止电机受淋损坏。 运输车辆不得靠近管沟行驶,装卸土方和材料与管沟保持一定距离。 加强对施工现场用电系统用电线路的管理,根据用电安全规定,对不符合安全规定及时拆除,加强电工巡回检查工作,发现隐患,及时排除。
本文档为【LPC基础教程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_842972
暂无简介~
格式:doc
大小:129KB
软件:Word
页数:67
分类:生活休闲
上传时间:2017-11-25
浏览量:163