已阅读5页,还剩27页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
QuickServer 开发手册(1)- 介绍 QuickServer 是一个免费的开源 Java 库,用于快速创建健壮的多线程、多 客户端 TCP 服务器应用程序。使用 QuickServer,用户可以只集中处理应用程 序的逻辑/协议,从而方便的建立功能强大的服务器应用。该程序由 Akshathkumar Shetty 设计和实现。 QuickServer 安装目录下的 example 中有演示其功能的例子,最新的例子 和文档可以通过网站 /或 /获得。 该指南适用于所有想要学习和使用 QuickServer 的人,阅读该指南应具备 基本的 Java 编程知识,基本的网络和 sockets 方面的知识也会有所帮助 1. 为什么需要 QuickServer? 无论何种编程语言,socket 编程对程序员来说都不是一件容易的事,创建 多线程、多客户端的服务器 socket 更像一场恶梦了。在每个新的软件中处理多 socket 连接,我们都要浪费大把时间编写大量重复的代码。QuickServer 因而 诞生使用 Java 创建多线程、多客户端服务器应用。 2. 基本构造 QuickServer 在应用逻辑上为开发者提供了四个类 o ClientCommandHandler 处理与客户端的交互使用字符串命令 o ClientObjectHandler 可选类 处理与客户端的交互使用对象命令 o Authenticator 可选类 客户端验证 o ClientData 可选类 客户端数据载体(支持类) 下面的图表显示了 QuickServer 库的基本构造。QuickServer 模块上七个辐条 表示七个方法: o java.lang.String info() o int getServiceState() o boolean initService(java.lang.Object config) o boolean startService() o boolean resumeService() o boolean suspendService() o boolean stopService() 与 QuickServer 模块相连接的四个组件中只有 ClientCommandHandler 是必 须的。 QuickServerConfig 对象由 initService()方法构建。它实现了 QuickServer,在读取 XML 配置后,QuickServerConfig 用于 QuickServer 配置。 ClientHandler 线程对象用于客户端缓冲池。可选的 ClientData 类与 ClientHandler 类关联,ClientHandler 对 象容器参考 ClientCommandHandler,ClientObjectHandler(可选),Authenticator(可选) 对象包含在 QuickServer 主函数中。 注意:上图中并未显示 QSAdminServer,它是图中 QuickServer 的组成部 分。 3. 主要特点 o 创建多线程、多客户端 TCP 服务器应用程序 o 支持安全服务的创建:SSL, TLS o 清楚的分离服务、协议、验证逻辑 o GUI 图形界面远程管理支持 o Command Shell 对服务器的本地管理 o 无须断开客户端连接的重启或延迟服务 o 为线程的再利用和大多数的使用对象建立缓冲池 o 完全的日志支持(Java 构建) o 支持发送和接收字符串、字节、二进制、序列化 Java 对象 o 在同样的 xml 中支持能够存贮指定应用数据的 XML 配置 o 支持通过 IP 地址限制服务 o 支持基于 XML 的 JDBC 映射 o 支持服务配置模式 o 支持从 xml 加载/重新加载用于 jar 包 o 在 QuickServer 中添加处理 hooks o 指定允许的最大客户端连接数 o 在通常的 TCP 连接上支持谈判安全连接 o 支持鉴别和查询客户端 o 附带典型例子FTPServer, CmdServer,EchoWebServer, ChatServer 4. 1.4 版的新功能 o 为 QuickServer 添加安全模式:SSL, TLS o 添加 SecureManagerLoader 管理安全模式 o 在通常的 TCP 连接上添加谈判安全连接 o 添加初始化服务 hooks o 为通信添加二进制模式 o 为 QsAdminServer 通信添加 QSAdminAPI o 为 QuickServer 添加 findAllClientByKey o 添加 ConnectionLostException 类 o 改进 ClientHandler、安全配置 o 新例子XmlAdder:一个简单的 xml 服务,可添加两个整数 o 新例子PipeServer:一个简单的重定向服务 QuickServer 开发手册(2)- 安装 1. 运行环境 QuickServer 1.2 以上的版本需要(其实在偶看来一个 1.4 版以上 JDK 足矣): 推荐 1.4 版以上 Java 虚拟机,最低 1.3 版(未经测试). Java Logging API(下列之一) o java.util.logging 包 JDK 1.4 版自带 o Lumberjack 库 / XML 解析器 (下列之一) o SAX (面向 XML 2.0 的 API) JDK 1.4 版自带 o JAXP (面向 XML 解析的 Java API) 1.1 JDK 1.4 版自带 o Xerces /xerces2-j o Crimson /crimson Jakarta 公共组件Digester, Pool o 这些产品包含在 Apache 开发的软件中(/)。Jar 包都 在以下的库中:BeanUtils, Collections, Logging. /commons/components.html. Apache 软件许可 证在文件“apache_license.txt”中。 2. 安装 目前最新的 1.4.1 版 QuickServer 可在 /download.html 下载。安装 QuickServer,假设 安装路径为$INSTALL_PATH。 在 CLASSPATH 中添加“$INSTALL_PATHdistQuickServer.jar“,在 PATH 中 添加“$INSTALL_PATHbin“。 另外测试 socket 的通讯软件推荐 SockTest,在 /soft/sockettest 可下载到最新版本。Windows 自带的 telnet 也可以进行测试。 QuickServer 开发手册(3)- 构建 EchoServer 学习怎样使用 QuickServer 库的一个好的方法是学习它提供的例子。在 QuickServer 安装路径下的 examples 文件夹里有许多典型的例子。 下面的章节里我们模仿其中的一个例子 EchoServer 来构建一个服务器。 EchoServer 是一个简单的 TCP 服务器,主要功能是将用户发送的字符串加上前 缀“Echo :“后返回。虽然这个例子可用性不强,但它是一个对 QuickServer 所 有特点的一个很好的示范。我们从构建一个最基本的服务器开始,以后慢慢给 它添加新的功能。 1. 代码 首先实现 EchoServer 最基本的功能:将用户发送的字符串加上前缀“Echo :“ 后返回。 在本地创建一个文件夹存放需要的代码,如在 c:projects中建立 echoserver 文件夹,然后创建一个类 EchoServer.java: 01 package echoserver; 02 03 import .*; 04 import .server.*; 05 06 import java.io.*; 07 08 public class EchoServer 09 public static void main(String s) 10 QuickServer myServer = 11 new QuickServer(“echoserver.EchoCommandHandler“); 12 myServer.setPort(4123); 13 myServer.setName(“EchoServer v 1.0“); 14 try 15 myServer.startServer(); 16 catch(AppException e) 17 System.err.println(“Error in server : “+e); 18 19 20 在第 10 行和第 11 行定义了一个 QuickServer 对象 myServer,通过一个 String 对象 “echoserver.EchoCommandHandler“声明了要加载的类,这个类面 向所有客户端做命令处理器,实现了 .server.ClientCommandHandler 接口,我们即将创建。 第 12 行设置了一个服务器端口用来做监听,然后设置整个应用的名字(第 13 行)。最后启动服务(第 15 行)。 接下来为 EchoServer 创建一个实现 .server.ClientCommandHandler 接口的类 EchoCommandHandler.java,用来处理服务器发送的命令。 01 / EchoCommandHandler.java 02 package echoserver; 03 04 import .*; 05 import java.io.*; 06 import .server.ClientCommandHandler; 07 import .server.ClientHandler; 08 09 public class EchoCommandHandler implements ClientCommandHandler 10 11 public void gotConnected(ClientHandler handler) 12 throws SocketTimeoutException, IOException 13 handler.sendClientMsg(“+“); 14 handler.sendClientMsg(“| Welcome to EchoServer v 1.3 |“); 15 handler.sendClientMsg(“| Send Quit to exit |“); 16 handler.sendClientMsg(“+“); 17 18 public void lostConnection(ClientHandler handler) 19 throws IOException 20 handler.sendSystemMsg(“Connection lost : “ + 21 handler.getSocket().getInetAddress(); 22 23 public void closingConnection(ClientHandler handler) 24 throws IOException 25 handler.sendSystemMsg(“Closing connection : “ + 26 handler.getSocket().getInetAddress(); 27 28 29 public void handleCommand(ClientHandler handler, String command) 30 throws SocketTimeoutException, IOException 31 if(command.equals(“Quit“) 32 handler.sendClientMsg(“Bye ;-)“); 33 handler.closeConnection(); 34 else 35 handler.sendClientMsg(“Echo : “+command); 36 37 38 根据 QuickServer 的要求,这个类必须实现 ClientCommandHandler 接口。 当客户端建立一个连接(11 行),gotConnected()方法被调用。在这个方 法里面,我们给客户端发送欢迎文本(13-16 行),这些文本使用通 过 ClientHandler 的 sendClientMsg()方法发送给客户端。我们也会使用 ClientHandler 的 sendSystemMessage()方法显示客户端连接的 InetAddress(20-21,25-26 行)。 handlerCommand()方法是 ClientCommandHandler 接口的核心方法,因为服 务器接收客户端发送的任何命令时都要调用该方 法。在我们对这个方法的实现 中,我们会检查命令是否为“Quit“(31 行),如果是,我们将发送一些提示文 本表示服务器即将关闭连接,然后关闭连接 (33 行)。否则,将命令加上前 缀“Echo :“返回给用户。 2. 运行和测试 o 运行命令提示符程序(cmd.exe) o 进入代码所在文件夹根目录,如 c:projects o 编译代码 javac echoserver*.java o 若无编译错误,运行服务器: set classpath=%classpath%;d:QuickServerdistQuickServer.jar;.(类所在 文件夹) java echoserver.EchoServer o 您将会看到如下信息: o 测试我们的服务器是否可以正常工作。再运行一个 cmd 程序,进入 SocketTest.jar 所在目录,键入 java -jar sockettest.jar 命令,弹出一个 窗口。在 IP Address 中输入““,在 Port 里输入“4123“,点击 “Connect“按钮,将看到窗口中显示如下图的信息。 若使用 telnet,可键入命令:open localhost 4123 在 Message 中输入一些字符串,点击“Send“按钮,浏览器将会返回一个加 了前缀“Echo :“的字符串。发送“Quit“,服务器断开连接。 QuickServer 开发手册(4)- 添加认证 现在我们给刚刚创建的服务器添加认证功能。 查看 .server.QuickServer 的文档(docs 文件夹下) 你可以注意到里面有一个方法 public void setAuthenticator(java.lang.String authenticator) 阅读文档可知此方法中的 authenticator 字符串是实现 .server.Authenticator 接口的方法的全名。 Authenticator 接口有两个实现: .server.QuickAuthenticator:这个类用来验证连接 QuickServer 的客户端。它只用一个实例处理所有的 QuickServer 验证。(推 荐) .server.ServerAuthenticator:这个类同样用来验 证连接 QuickServer 的客户端,但对每一个验证的处理都会创建一个实例。 接下来给 EchoServer 加验证功能。简单点,客户端输入的用户名和密码一 致就算验证通过。 首先,在同样的文件夹里创建一个验证类: EchoServerQuickAuthenticator 01 package echoserver; 02 03 import .server.*; 04 import java.io.*; 05 06 public class EchoServerQuickAuthenticator extends QuickAuthenticator 07 08 public boolean askAuthorisation(ClientHandler clientHandler) 09 throws IOException 10 String username = askStringInput(clientHandler, “User Name :“); 11 String password = askStringInput(clientHandler, “Password :“); 12 13 if(username=null | password =null) 14 return false; 15 16 if(username.equals(password) 17 sendString(clientHandler, “Auth OK“); 18 return true; 19 else 20 sendString(clientHandler, “Auth Failed“); 21 return false; 22 23 24 这个类扩展了 .server.QuickAuthenticator(第 6 行),在 askAuthorisation()方法中(8 行),通过 askStringInput()方法要 求客户端输入用户名和密码,并读入客户端输入的信息 (10-11 行)。这个方 法继承自 QuickAuthenticator。如果用户名与密码相等,发送正确信息并返回 “true“(16-18 行),否则 发送错误信息并返回“false“(20-21 行)。 接下来我们要告诉 QuickServer 使用我们新创建的验证类来做验证器。修 改前一章创建的 EchoServer.java 文件,代码如下(粗体为修改的代码): 01 package echoserver; 02 03 import .*; 04 import .server.*; 05 06 import java.io.*; 07 08 public class EchoServer 09 10 public static void main(String s) 11 12 QuickServer myServer = 13 new QuickServer(“echoserver.EchoCommandHandler“); 14 myServer.setAuthenticator( 15 “echoserver.EchoServerQuickAuthenticator“); 16 myServer.setPort(4123); 17 myServer.setName(“EchoServer v 1.0“); 18 try 19 myServer.startServer(); 20 catch(AppException e) 21 System.err.println(“Error in server : “+e); 22 23 24 OK,将修改好的文件编译,按照前一章讲述的方法运行程序。这次当我们 点击“Connect“时,浏览器会要求我们输入用户名和密码。如果输入的用户名和 密码一致就可以登录。如果输入错误五次以上,浏览器会提示“-ERR Max Auth Try Reached“并自动断开连接。这个次数和提示信息可以通过 QuickServer 类 的 setMaxAuthTry() 和 setMaxAuthTryMsg()修改。 有时在验证过程中我们可能需要中途退出而不是等待验证结束,这时输入 “Quit“是不起作用的。我们可以这样修改代码,有两个方法: 一是从 EchoServerQuickAuthenticator 类中的 askAuthorisation()方法 抛出一个 .AppException 异常,代码如下: String username = askStringInput(clientHandler, “User Name :“); if (username != null throw new AppException(“Quit“); 或者参考 ClientHandler,关闭连接,代码如下: String username = askStringInput(clientHandler, “User Name :“); if (username != null clientHandler.closeConnection(); return false; ClientHandler 对象能够提供很多客户端连接的有用信息,如 IP 地址。更 多信息请参考 API 文档。 注意: o 不要在验证器类中存贮任何客户端相关信息,如果需要,必须存放在 ClientData 类中-下一章将讲解该部分内容。 o 必须确认 askAuthorisation()方法是线程安全的。 QuickServer 开发手册(5)- 客户数据 既然不能在 ClientCommandHandler 和 ServerAuthenticator 类中保存客户 数据,我们使用 ClientData 类的 handleCommand()或 askAuthorisation()方法 来存储所有的客户端信息。 示范一下这个特点有什么用。还是以 EchoServer 为例,当用户发送 “Hello“时,我们给他一个问候。如果用户再发送“Hello“,我们提醒他已经发 了 n 次“Hello“。接下来定义 ClientData 类来存储用户名以及他向服务器发送 “Hello“的次数。 1. 代码 1. 在 EchoServer 中创建一个 EchoServerData 类 01 /- EchoServerData.java - 02 package echoserver; 03 04 import .server.*; 05 import java.io.*; 06 07 public class EchoServerData implements ClientData 08 private int helloCount; 09 private String username; 10 11 public void setHelloCount(int count) 12 helloCount = count; 13 14 public int getHelloCount() 15 return helloCount; 16 17 18 public void setUsername(String username) 19 this.username = username; 20 21 public String getUsername() 22 return username; 23 24 25 /- end of code - 2. 告诉 QuickServer 用这个 EchoServerData 来做为它的 ClientData 类。 修改前面创建的 EchoServer.java,代码如下: 01 package echoserver; 02 03 import .*; 04 import .server.*; 05 06 import java.io.*; 07 08 public class EchoServer 09 public static void main(String s) 10 11 String cmd = “echoserver.EchoCommandHandler“; 12 String auth = “echoserver.EchoServerQuickAuthenticator“; 13 String data = “echoserver.EchoServerData“; 14 15 QuickServer myServer = new QuickServer(cmd); 16 myServer.setAuthenticator(auth); 17 myServer.setClientData(data); 18 19 myServer.setPort(4123); 20 myServer.setName(“Echo Server v 1.0“); 21 try 22 myServer.startServer(); 23 catch(AppException e) 24 System.out.println(“Error in server : “+e); 25 26 27 上面的代码中,我们将配置信息写入 String 对象来设置 QuickServer。 3. 修改 Authenticator 类,也就是 EchoServerAuthenticator 类,让它在 ClientData 对象中存储用户名。下面是修改后的代码: 01 package echoserver; 02 03 import .server.*; 04 import java.io.*; 05 06 public class EchoServerQuickAuthenticator extends QuickAuthenticator 07 08 public boolean askAuthorisation(ClientHandler clientHandler) 09 throws IOException 10 String username = askStringInput(clientHandler, “User Name :“); 11 if(username!=null 13 /close the connection 14 clientHandler.closeConnection(); 15 return false; 16 17 18 String password = askStringInput(clientHandler, “Password :“); 19 20 if(username=null | password =null) 21 return false; 22 23 if(username.equals(password) 24 sendString(clientHandler, “Auth OK“); 25 /store the username in ClientData 26 EchoServerData data = (EchoServerData)clientHandler.getClientData(); 27 data.setUsername(username); 28 return true; 29 else 30 sendString(clientHandler, “Auth Failed“); 31 return false; 32 33 34 4. 修改 ClientCommandHandler 实现类 EchoCommandHandler。如果用户发送 “Hello“,给他一个问候。如果他发送多次“Hello“,告诉他已经发送了 n 次 “Hello“。下面是修改后的代码: 01 / EchoCommandHandler.java 02 package echoserver; 03 04 import .*; 05 import java.io.*; 06 import .server.ClientCommandHandler; 07 import .server.ClientHandler; 08 09 public class EchoCommandHandler implements ClientCommandHandler 10 11 public void gotConnected(ClientHandler handler) 12 throws SocketTimeoutException, IOException 13 handler.sendClientMsg(“+“); 14 handler.sendClientMsg(“| Welcome to EchoServer v 1.0 |“); 15 handler.sendClientMsg(“| Note: Password = Username |“); 16 handler.sendClientMsg(“| Send Quit to exit |“); 17 handler.sendClientMsg(“+“); 18 19 public void lostConnection(ClientHandler handler) 20 throws IOException 21 handler.sendSystemMsg(“Connection lost : “ + 22 handler.getSocket().getInetAddress(); 23 24 public void closingConnection(ClientHandler handler) 25 throws IOException 26 handler.sendSystemMsg(“Closing connection : “ + 27 handler.getSocket().getInetAddress(); 28 29 30 public void handleCommand(ClientHandler handler, String command) 31 throws SocketTimeoutException, IOException 32 if(command.equals(“Quit“) 33 handler.sendClientMsg(“Bye ;-)“); 34 handler.closeConnection(); 35 if(command.equalsIgnoreCase(“hello“) 36 EchoServerData data = (EchoServerData) handler.getClientData(); 37 data.setHelloCount(data.getHelloCount()+1); 38 if(data.getHelloCount()=1) 39 handler.sendClientMsg(“Hello “+data.getUsername(); 40 else 41 handler.sendClientMsg(“You told Hello “+data.getHelloCount()+ 42 “ times. “); 43 44 else 45 handler.sendClientMsg(“Echo : “+command); 46 47 48 5. 编译改好的程序,运行,使用 SocketTest 测试。登录后,发送“Hello“,系 统会给一个问候,再次发送“Hello“,它将告诉你发送了多少次“Hello“。 4.2 创建 ClientData 池 现在我们知道 ClientData 可以正常工作了。但是对每一个连接 QuickServer 的客户端都要创建一个新的 ClientData 对象,可能会造成性能上 的瓶颈,尤其对性能要求较高的服务器来说。 我们可以创建一个 ClientData 池对象,无论客户端什么时候进行连接,都 使用同一个对象。首先实现下面的接口: org.quickserver.util.pool.PoolableObject 查找 QuickServer API 文档可以发现 PoolableObject 只有两个必须实现的 方法: mons.pool.PoolableObjectFactory 属于通常的工厂方法。 isPoolable()判断对象是否可以成为池对象。 PoolableObjectFactory mons.pool.PoolableObjectFactory 接口包含了以下方法: o void activateObject(Object obj):重新初始化一个实例。 o void destroyObject(Object obj):销毁一个不再需要的实例。 o Object makeObject():创建一个实例。 o void passivateObject(Object obj):禁止初始化一个实例。 o boolean validateObject(Object obj):确定一个实例是否安全。 我们可以扩展一个基于无操作的实现来创建可“池“化的对象: mons.pool.BasePoolableObjectFactory 这个类只有一个抽象方法 makeObject()和一个 validateObject()方法,它 只返回 true。 我们来创建一个 EchoServerPoolableData 类。 01 /- EchoServerPoolableData.java - 02 package echoserver; 03 04 import .server.*; 05 import java.io.*; 06 07 public class EchoServerPoolableData 08 extends EchoServerData 09 implements mons.pool.PoolableObjectFactory 10 11 public void activateObject(Object obj) 12 13 public void destroyObject(Object obj) 14 if(obj=null) return; 15 passivateObject(obj); 16 obj = null; 17 18 public Object makeObject() 19 return new EchoServerPoolableData(); 20 21 public void passivateObject(Object obj) 22 EchoServerPoolableData pd = (EchoServerPoolableData)obj; 23 pd.setHelloCount(0); 24 pd.setUsername(null); 25 26 public boolean validateObject(Object obj) 27 if(obj=null) 28 return false; 29 else 30 return true; 31 32 33 /- end of code - 这个类扩展了我们的 EchoServerData,然后我们实现了 mons.pool.BasePoolableObjectFactory,这个实现是简单的不 需要解释了。 现在我们需要告诉 QuickServer 使用这个类来代替原来的 ClientData 类。 myServer.setClientData(“echoserver.EchoServerPoolableData“); 编译修改的程序,可能会报如下错误: package mons.pool does not exist。 这是因为编译器不知道这个类。可以在环境变量中添加 D:QuickServerdistcommons-pool.jar 包,并在运行时 set classpath=%classpath%;d:QuickServerdistQuickServer.jar; d:QuickServerdistcommons-pool.jar;.(类所在文件夹)即可。 QuickServer 开发手册(6)- 远程管理支持 我们的 EchoServer 可能需要修改几个服务器配置参数,如超时消息、最多验证数、最大验 证时间。QuickServer 支持这些功能而无须改变代码。 1. 使用 QSAdminServer 当我们需要一个管理服务器来控制我们的服务器时,我们不需要修改代码甚至关闭正在 运行的服务器。这项服务的实现类是: .qsadmin.QSAdminServer 要使用它的功能我们要调用 QuickServer 的 startQSAdminServer()方法。QSAdminServer 运行的默认端口是 9876,我们可以使用下面两个方法之一修改它: setQSAdminServerPort(4124); getQSAdminServer().getServer().setPort(4124); 下面是能够在 EchoServer 的 4124 端口运行 QSAdminServer 的代码: 01 package echoserver; 02 03 import .*; 04 import .server.*; 05 06 import java.io.*; 07 08 public class EchoServer 09 public static void main(String s) 10 11 String cmd = “echoserver.EchoCommandHandler“; 12 String auth = “echoserver.EchoServerQuickAuthenticator“; 13 String data = “echoserver.EchoServerPoolableData“; /Poolable 14 15 QuickServer myServer = new QuickServer(cmd); 16 myServer.setAuthenticator(auth); 17 myServer.setClientData(data); 18 19 myServer setPort(4123); 20 myServer.setName(“Echo Server v 1.0“); 21 22 /config QSAdminServer 23 myServer.setQSAdminServerPort(4124); 24 myServer.getQSAdminServer().getServer().setName(“EchoAdmin v 1.0“); 25 try 26 myServer.startQSAdminServer(); 27 myServer.startServer(); 28 catch(AppException e) 29 System.out.println(“Error in server : “+e); 30 31 32 33 这样,我们定义了我们的 QSAdminServer 运行在 4124 端口。但是它怎样进 行验证呢?如果没有一个外在的验证器,QSAdminServer 将 使用 .qsadmin.Authenticator 做为它的验证器。查阅 API 文 档我们可以发现它非常简单,用户 名和密码都被硬编码为: 用户名 : Admin 密码 : QsAdm1n 现在让我们编译新的程序并运行之,控制台将会输出信息以说明服务器运 行于 4124 端口。 在 QuickServer 安装目录下的 bin 目录下运行 QsAdminGUI.bat,QsAdmin 的界面如下所示 现在可以连接到管理服务器了。点击右上角的“Login“按钮,将会弹出一个登录对话框如下 图,输入 IP 地址和服务器运行端口:、4124,因为我们使用默认的用户名密码, 直接点击“Login“登录。 登录后界面将会显示欢迎及登录成功信息。现在可以选择发送命令的目标服务器 (Target)及左边一排命令按钮所示的操作。 Target 是基于发送命令的服务器,因为我们目前有两个服务器 EchoServer 和 EchoAdmin。 界面右下边有一个可以直接向服务器发送消息的文本框,命令可以参考 QsAdmin command handler: .qsadmin.CommandHandler API 文档
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 上下游协议合同范本
- 公司弃权协议书范本
- 江西九江市社会保险局2025年下半年招考编制外工作人员易考易错模拟试题(共500题)试卷后附参考答案
- 机构老师陪读协议书
- 杭州市医疗保健服务中心2025年下半年招考工作人员易考易错模拟试题(共500题)试卷后附参考答案
- 卫生院与卫生协议书
- 树木占用补偿协议书
- 广州市荔湾区规划设计所2025年下半年招考2名专业技术人员易考易错模拟试题(共500题)试卷后附参考答案
- 供暖维修协议书范本
- 广东省广州市白云区2025年下半年事业单位招聘208人易考易错模拟试题(共500题)试卷后附参考答案
- (2025)医保知识试题附及答案
- T/CCSAS 022-2022危险化学品企业泄漏管理导则
- 共享出行市场:2025年竞争格局演变与商业模式创新策略
- 合成生物学技术突破及其在生物制造领域的应用前景
- 常见安全隐患依据库:一、电气类
- 认知障碍患者进食问题评估及处理
- 2025智联招聘行测题库及答案解析
- 统编人教版二年级语文下册《中国美食》教学课件
- GB/T 12643-2025机器人词汇
- 药物外渗和渗出的预防和处理
- Unit5 What does he do?A lets talk(说课稿)-2024-2025学年人教PEP版英语六年级上册
评论
0/150
提交评论