已阅读5页,还剩23页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
(综合课程实习2)设计说明书基于C/S模式的即时通信系统 (使用TCP协议实现)起止日期: 2013 年 12 月 16日 至 2014 年 1 月 3 日学生姓名不告诉你班级不告诉你学号不告诉你成绩指导教师(签字)计算机与通信学院2013年 12 月26 / 28 摘要即时通信(Instant Message),由于其具有实时性、跨平台性、成本低、效率高等优点而受到广泛的使用。设计并实现一个能够处理多用户进行实时、安全的即时通信系统具有较强的现实意义。即时通信的底层通信是通过SOCKET套接字接口实现的。当前的主流UNIX系统和微软的WINDOWS系统都在内核提供了对SOCKET字接口的支持。使用这个统一的接口,可以编写一个可移植的TCP/IP通信程序。使信息能够在INTERNET上可靠的传输。本文设计并实现了基于局域网内的简单即时通信系统,系统采用C/S模式,底层通信通过SOCKET套接字接口实现,服务器负责客户端的登录验证,好友信息的保存和心跳报文的发送。客户端采用P2P方式实现消息传递,并能实现文件的传输。本文首先讨论了同步套接字,异步套接字,多线程并发执行任务等;然后阐述了客户端、服务器如何使用XML序列化的消息进行通信。关键词:即时通信,文件传输,套接字,TCP协议目 录一 绪论3 1.目的32.意义3二 需求分析42.1 需求42.2相关技术介绍42.2.1.NET开发平台及C.NET开发语言42.2.2 TCP协议52.3 套接字52.4 C/S模型62.5 即时通信协议6三 系统总体设计73.1系统基本架构73.2功能模块设计7 3.3逻辑图93.4数据库设计10 3.4.1实体关系图10 3.4.2 详细列表10四 系统详细设计114.1使用XML定义的即时通信协议114.1.1信息结构MESSAGE.CS&UMESSAGE.CS114.1.2数据结构FriendStruct134.2数据库连接类144.3服务器端154.3.1同步套接字网络监听154.3.2 多线程194.3.3计时器194.4客户端204.4.1 同步套接字客户端214.4.2 采用异步套接字的文件传输23五 心得体会26六 参考文献27一 绪论1.目的 综合课程实习是网络工程专业的重要实践性环节,是学生在学校期间对前期主要课程内容的一次综合训练。综合课程实习为学生提供了一个既动手又动脑、独立实践的机会,并且将课本上的理论知识和实际有机地结合起来。通过综合课程实习,可以进一步巩固学生所学专业知识,加深对专业的了解,扩大专业知识面,提高发现问题、分析问题与解决问题的实际能力,为后继专业课程的学习打下良好的基础。 2.意义 最早的即时通信软件是ICQ,ICQ是英文中I seek you的谐音,意思是我找你。四名以色列青年于1996年7月成立Mirabilis公司,并在11月份发布了最初的ICQ版本,在六个月内有85万用户注册使用。在因特网上受欢迎的即时通信服务包含了MSN Messenger、AOL Instant Messenger、Yahoo! Messenger、NET Messenger Service、Jabber、ICQ与QQ。 这些服务有赖于许多想法更久的(与普遍)的在线聊天媒介,如Internet Relay Chat一样知名。1970年代早期,一种更早的即时通信形式是柏拉图系统(PLATO system)。之后在1980年代,UNIX/Linux的交谈实时信息被广泛的使用于工程师与学术界,1990年代即时通信更跨越了因特网交流。1996年11月,ICQ是首个广泛被非UNIX/Linux使用者用于因特网的即时通信软件。在ICQ的介绍之后,同时在许多地方有一定数量的即时通信方式发展,且各式的即时通信程序有独立的协议,无法彼此互通。这引导使用者同时执行两个以上的即时通信软件,或者他们可以使用支持多协议的终端软件,如Gaim、Trillian或Jabber。近年来,许多即时通信服务开始提供视讯会议的功能,网络电话(VoIP),与网络会议服务开始整合为兼有影像会议与实时信息的功能。于是,这些媒体的分别变的越来越模糊。二 需求分析2.1 需求 (1)即时通信是一个终端连往一个即时通信网路的服务。即时通信不同于e-mail在于它的交谈是实时的。大部分的即时通信服务提供了presence awareness的特性显示联络人名单,联络人是否在在线与能否与联络人交谈。近年来,许多即时通信服务开始提供视讯会议的功能,网络电话(VoIP),与网络会议服务开始整合为兼有影像会议与实时信息的功能。于是,这些媒体的分别变的越来越模糊。 (2)本课题目标是实现局域网用户之间的即时交流和文件传输,通过基础的网络SOKET编程,为局域网内部的即时通信提供一个简单而较安全的解决方案。 (3)本系统采用C/S(Client/Server)结构进行设计,使用SQL Server 2000构建数据库,并在.NET环境下使用Visual C#.net语言和SOCKET套接字开发一个基于TCP协议的简单即时通信软件,实现简单的即时聊天,文件传输等功能。 (4)功能:客户管理(注册和登陆);显示在线用户;支持私聊;多人同时在线聊天(群聊)。 (5)软件针对局域网内部用户,实现用户间的即时通信。需要分别实现服务器端和客户端的软件设计。 (6)服务器端负责监听用户连接请求,负责连接数据库存储用户信息,负责发送给用户好友信息,负责发送心跳报文检查用户在线状态并即时让用户更新好友在新信息。 (7)客户端发起主动连接,向服务器请求登录或者注册。客户端可以修改昵称,可以加已知用户为好友(类似于MSN的好友添加功能)。客户端之间可以发起P2P模式的聊天,可以传送文件。2.2相关技术介绍2.2.1.NET开发平台及C.NET开发语言.NET框架是Microsoft公司推出的一种全新的开发平台,提供了统一的、面向对象并且可以扩展的编程类库和完善的集成开发环境,大大简化了应用程序的开发过程,并且具有良好的移植性和安全性。微软为了推行.NET战略,特别为.NET平台设计了一种语言C#。C#是由C和C+派生而来的一种“简单、流行、面向对象、类型安全”的程序设计语言,其综合了Visual basic的高效率和C+的强大功能,然而更多的人感觉C#更类似JAVA。事实上C#融合了大量的JAVA思想,C#是.NET的关键性语言,它是整个.NET平台的基础。与C#相比,.NET所支持的其它语言显然是配角,包括VC+.NET在内。但是微软并没有打算放弃VC+.NET,相反,微软对VC+.NET有着另一番独特的打算,VC+.NET的定位与C#不完全重合,VC+.NET应用范围仍强于C#,这一点无论对微软公司还是软件业应用现状都非常重要。2.2.2 TCP协议面向连接的通信可以使用可靠通信,在这时候,第四层协议发送数据接收方的确认,如果未收到数据或者数据被损坏,则请求重新传输。TCP协议就使用这种可靠通信。使用TCP协议的应用层协议包括HTTP、FTP、SMTP和Telnet等。TCP要求在发送数据之前必须打开连接。服务器应用程序必须执行一个称作被动打开(passive open)的操作,以利用一个已知的端口号创建一个链接,这是,服务器并不是对网络进行呼叫,而是侦听并等待引入的请求。客户应用程序必须执行一个主动打开(active open),为此,它向服务器应用程序发送一个同步序列号(SYN)以标识连接。客户应用程序可以将动态端口号作为本地端口使用。服务器必须向客户发送一个确认(ACK)以及服务器的序列号(SYN)。随后,客户回复一个ACK,这样就建立了链接。现在可以发送和接收消息了。接收消息后,总是返回ACK消息。如果在收到ACK之前发送方已经超时,则消息将被放到重发队列中以再次发送。由于它的握手机制,所以TCP协议比较复杂并且费时,但此协议在处理数据时对数据包的传送有保障,从而使得在应用程序协议中不需要再包括该功能。2.3 套接字套接字这个术语并没有定义某个协议:它具有两层含义,但两者都与一个协议相关。第一个含义是套接字编程API,它最初由伯克利大学为BSD UNIX而创建。BSD套接字在经过修改后被用作Windows环境的编程接口(并且被命名为WinSock)。WinSock API被包装在System.Net.sockets命名空间的.NET类中。Windows Sockets 是一个独立于协议的编程接口,用于编写网络应用程序。套接字的第二层含义表示一个用于在进程间进行通信的终端。在TCP/IP中,每个终端都与一个IP地址和一个端口号绑定。我们必须对流式套接字和数据报套接字这两种类型进行区分。流失套接字用TCP/IP协议来使用面向连接的通信;另一方面,数据报套接字用UDP/IP来使用无连接通信。2.4 C/S模型客户机/服务器模型,又称为Client/Server模型,简称C/S架构。C/S计算技术在信息产业当中占有重要的地位。这种客户机/服务器模型是一种非对称式编程模式。该模式的基本思想是把集中在一起的应用划分成为功能不同的两个部分,分别在不同的计算机上运行,通过它们之间的分工合作来实现一个完整的功能。对于这种模式而言其中一部分需要作为服务器,用来响应并为客户提供固定的服务;另一部分则作为客户机程序用来向服务器提出请求或要求某种服务。 在此“服务器”是指能在网络上提供服务的任何程序。服务器接受网络上的请求,完成服务后将结果返回给申请者。对于简单的服务,把每个请求用一个IP数据报发给服务器,服务器用另一个数据报返回响应。客户机和服务器都是独立的计算机。当一台连入网络的计算机向其他计算机提供各种网络服务(如数据、文件的共享等)时,它就被叫做服务器。而那些用于访问服务器资料的计算机则被叫做客户机。严格说来,客户机/服务器模型并不是从物理分布的角度来定义,它所体现的是一种网络数据访问的实现方式。采用这种结构的系统目前应用非常广泛。如宾馆、酒店的客房登记、结算系统,超市的POS系统,银行、邮电的网络系统等。各种网络服务器基本都遵循同样的算法:创建一个端口(Port),接受从网络上来的客户服务请求,完成计算后把结果返回给客户,如此反复。2.5 即时通信协议协议是一系列的步骤,它包括双方或者多方,设计它的目的是要完成一项任务。即时通信协议,参与的双方或者多方是即时通信的实体。协议必须是双方或者多方参与的,一方单独完成的就不算协议。这样在协议动作的过程中,双方必须交换信息,包括控制信息、状态信息等等。这些信息的格式必须是协议参与方同意并且遵循的。好的协议要求清楚,完整,每一步都必须有明确的定义,并且不会引起误解;对每种可能的情况必须规定具体的动作。有许多的 IM 系统,如 AOL IM、Yahoo IM 和 MSN IM,它们使用了不同的技术,而且它们互不兼容。为了创建即时通信的统一标准,人们经过了多次尝试:IETF 的对话初始协议(SIP)和 即时通信对话初始协议和表示扩展协议(SIMPLE)、应用交换协议(APEX)、显示和即时通信协议(PRIM)及基于 XML 且开放的可扩展通信和表示协议(XMPP)协议(常称为 Jabber 协议)。人们多次努力,试图统一各大主要 IM 供应商的标准(AOL、Yahoo 及 Microsoft),但无一成功,且每一种 IM 仍然继续使用自己所拥有的协议。 三 系统总体设计 3.1系统基本架构基于C/S架构的即时通信软件便于对用户信息进行统一管理和保存,面向特定的用户,对信息的安全控制能力很强。为了减轻服务器负担,客户端之间的信息传递是采用P2P模式的,服务器只负责用户的注册,登录和用户在线状态的检验。基本结构如图:图1 系统基本架构 3.2功能模块设计CLIENT:1. 注册:(1) 可以完成客户端注册,客户端可以通过填写信息进行注册,信息被发送到服务器端。2. 登录:(1) 客户可以输入账号和密码进行登录,客户端会发送登录信息等待服务器响应,登录成功后会发出登录成功信息并刷新好友列表。3. 修改:(1) 密码修改:应该有密码修改功能(2) 信息修改:可以更改一些注册信息4. 通信:(1) 即时聊天模块:客户端与客户端之间建立线程进行即时聊天,也包含有简单的对称加解密算法功能。(2) 好友列表:可以对好友列表进行添加删除等动作5. 文件传输:(1) 文件传输:文件传输功能SERVER:1. 注册回应:对客户端传送的注册信息进行判断。(1) HASH加密:对用户的账号和密码信息进行HASH加密(2) 重复用户检查:将加密后信息与已存在账号进行比较,检查是否账号已存在,如果存在就返回错误信息(3) 注册成功:将可成功注册的用户账号和密码写入数据库内,并向客户端返回成功信息2. 修改回应:(1) 对密码和信息修改请求进行判断,执行和返回修改成功信息3. 登录回应:(1) 对登录的账号和密码进行加密检查后发回正确或错误情况,并记录上线信息(2) 好友列表发送:给成功登录的账号发送好友列表及好友上线信息(3) 上线信息发送:给成功登录的账号的好友发送在线信息(包括IP,端口等等信息)4. 在线情况:(1) 对登录,在线,离线的用户情况进行统计,记录和通知(2) 心跳测试:每隔一段时间发送报文测试用户是否因意外原因离线(3) 情况记录:将用户登录时间,IP,下线时间等信息记录入数据库 3.3逻辑图图2 逻辑图3.4数据库设计3.4.1实体关系图服务器是作为记录和读取数据库信息的载体,与客户端关系并不复杂,这里需要重点考虑客户端之间的关系。用户与用户之间的关系是较为特殊的递归关系,即描述发生在两个相同实体上的关系。E-R图如下:聊天文件传输nn用户ID好友ID状态IP客户端账号昵称EmailID密码好友分组状态客户端账号昵称EmailID密码好友分组IP图3 E-R图3.4.2 详细列表数据库包含两个表,分别为记录用户信息的TCP_Userinfo和记录用户好友信息的TCP_Friendinfo。详细设计见下面两表:表1 用户信息表TCP_UserInfoTCP_Userinfo列(属性)名类型主键宽度是否允许为空备注UserIDnumericY9NOT NULL自增长UserAccountncharN20NOT NULL用户帐号UserNicknamencharN20NOT NULL用户昵称,可重复UserEmailncharN20NOT NULL用户EMAILJoinDatencharN35NOT NULL注册日期LastLoginncharY20NOT NULL最后登录IPUserIPncharY20NOT NULL用户IPUserFavvarcharN100NOT NULL用户好友分组,有默认值UserQuestionncharY20NOT NULL密码问题UserAnswerncharY20NOT NULL密码答案UserPasswordncharN20NOT NULL用户密码UserOnlineintN4NOT NULL在线状态,1在,0不在表2 用户好友表TCP_FriendInfoTCP_Userinfo列(属性)名类型主键宽度是否允许为空备注InfoIDnumericY9NOT NULL自增长UserIDncharN20NOT NULL用户IDFriendIDncharN20NOT NULL用户好友IDFriendGroupncharN20NOT NULL用户好友分组四 系统详细设计 4.1使用XML定义的即时通信协议 4.1.1信息结构MESSAGE.CS&UMESSAGE.CS这两个C#类定义了包括服务器信息,状态信息,注册信息,登录信息,聊天信息或者请求文件传输信息的函数,服务器和客户端通过将它们实例化和序列化再转换成流在网络上进行传输。UMESSAGE.CS主要代码如下: Serializable public class UMessage public UMessage() private string _nickname; private string _password; private string _accounts; private string _email; private int _info;/表示注册或者登录信息,客户端信息0为注册,1为登录;服务器返回信息0为用户已存在,1为注册成功,2为服务器未知错误,3为CLIENT在线检查,10为登录失败,11为登录成功 private Friend _friend; private int _fn; private string _fg; public string Nickname get return _nickname; set _nickname = value; public string Password get return _password; set _password = value; public string Accounts get return _accounts; set _accounts = value; public string Email get return _email; set _email = value; public int Info get return _info; set _info = value; public Friend Fri get return _friend; set _friend = value; public int Fn get return _fn; set _fn = value; public string Fg get return _fg; set _fg = value; 由于MESSAGE.CS与UMESSAGE.CS类似,在此不再详述。服务器和客户端都可以通过相同的代码对UMESSAGE赋值,再通过XmlSerializer方法进行将UMESSAGE序列化为XML文档,最后将XML文档转化为网络流进行传输。代码如下:#region 将登录信息转为UMessageprivate void Traslator()_message.Accounts=this.TextBox1.Text;_message.Nickname=;_message.Password=this.TextBox2.Text;_message.Email=;_message.Info=1;_message.Fri=null;#endregion4.1.2数据结构FriendStruct服务器如果保存和传递用户的好友信息是难点之一。数据库的设计和信息的传递辨别都是比较难实现的。在数据库方面,每个用户拥有各自的好友分组信息(UserFav),分组中间使用“,”分隔,在TCP_FriendInfo表中则分别保存了用户ID和好友ID,使用一个INT字段保存分组信息。数据库以用户ID为标准对好友ID和分组信息进行内连接查询,就可以得到基本的好友信息了。代码如下:select * from TCP_UserInfo join TCP_FriendInfo on TCP_FriendInfo.UserID= + uid + and TCP_UserInfo.UserID=TCP_FriendInfo.FriendID在好友信息的传输方面,首先定义一个FriendStruct数据结构(当然也可以用枚举完成)如下:using System;using System.Collections.Generic;using System.Text;namespace TCP public class FriendStruct public struct FileInfo public int filere;/接收和拒绝信息,1为接收,2为拒绝,3为取消 public string filename; public long filelength; public struct Friend public string account; public string nickname; public string IP; public string status; public string fg;/好友分组 在MESSAGE.CS或者UMESSAGE.CS中,我们则定义了FriendStruct的数组。在C#中使用DATAREADER语句可以逐句读取数据库查询的结果,再依次将结果赋值FriendStruct数组元素,就得到了便于发送和读取的存放好友信息的数组。赋值代码如下: while (getf.Read()/getf即是以上的数据库查询的datareader语句 ffi.account=getfUserAccount.ToString(); ffi.IP = getfUserIP.ToString(); ffi.nickname = getfUserNickname.ToString(); ffi.status = getfUserOnline.ToString(); ffi.fg = getfFriendGroup.ToString(); i+; getf.Close();4.2数据库连接类实现一个快捷简单的数据库连接的相关代码是非常有必要的。实现的途径也多种多样,鉴于安全性和复杂性的需求不同,实现方法有简有繁。本设计使用了一个简单的类(UserData.CS)实现了简单快捷的数据库连接和读取。主要代码如下: public static SqlConnection connStr = new SqlConnection(Server=D96B85DD938A465.;uid=sa;pwd=change;database=TCPDB); public static SqlDataReader SqlReader(string sql, SqlConnection connstr) SqlDataReader sqldr = null; SqlCommand cmd = new SqlCommand(sql, connstr); if (cmd.Connection.State.ToString() = Closed) cmd.Connection.Open(); try sqldr = cmd.ExecuteReader(); catch (Exception e) if (e != null) sqldr = null; return sqldr; /数据库操作连接 public static string SqlCmd(string sql, SqlConnection connstr) string errorstr = null; SqlCommand sqlcmd = new SqlCommand(sql, connstr); if (sqlcmd.Connection.State.ToString() = Open) sqlcmd.Connection.Close(); sqlcmd.Connection.Open(); try sqlcmd.ExecuteNonQuery(); catch (Exception e) if (e != null) errorstr = e.ToString(); sqlcmd.Connection.Close(); return errorstr; 在UserData.CS的基础上,主程序可以更方便地实现数据库连接操作,对数据库进行读写和更新,在此不再详述。4.3服务器端这里显示传入的原始信息服务器端的界面设计是基于便于测试的目的而实现的。如下图:这里显示已连入的连接图4 服务器端界面4.3.1同步套接字网络监听基于同步套接字的网络监听器对服务器来说并不是最好的解决方案,但是仍然可行并且实现简单。主要代码如下:开启监听端口: public void Serve() int port = 8888; ServerIPEP = new IPEndPoint(IPAddress.Any, port); s = new Socket(ServerIPEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); s.Bind(EndPoint)ServerIPEP); s.Listen(10); alSock = new ArrayList();以下代码读取连入的连接,依次将连接加入可变长数组alsock,并且读取传入的信息,进行反串行化: while (true) try uc = s.Accept(); alSock.Add(uc); this.tb_states.AppendText(System.Convert.ToString(uc); byte data = new byte2048; int rect = uc.Receive(data); byte chat = new byterect; Buffer.BlockCopy(data, 0, chat, 0, rect); UMessage umessage = (UMessage)_translator.Deserialize(new MemoryStream(chat); int info = umessage.Info;对反串行化后的信息进行处理,通过info参数辨认客户端行为(注册或者登录),对注册的信息进行数据库查询,注册信息可插入,则将用户信息插入数据库,否则返回客户端“注册出错”的信息: #region 处理用户注册信息 if (info=0)/分辨出用户发送的是注册信息 string Accounts = umessage.Accounts; SqlDataReader usdr = FPara.SqlReader(select * from TCP_UserInfo where UserAccount= + Accounts + , FPara.connStr); if (usdr != null) if (usdr.Read() #region 此处写入返回注册失败的代码 Socket sc = (Socket)alSockalSock.IndexOf(uc, 0); sc.Send(chat); #endregion else #region 此处写入插入数据库用户注册信息的代码 Stream ms = new MemoryStream(); Socket sc = (Socket)alSockalSock.IndexOf(uc, 0); if (FPara.SqlCmd(insert into TCP_UserInfo (UserAccount,UserNickname,UserEmail,JoinDate,UserIP,UserPassword) values( + umessage.Accounts + , + umessage.Nickname + , + umessage.Email + , + System.DateTime.Now.ToString() + , + (IPEndPoint)uc.RemoteEndPoint).Address.ToString() + , + umessage.Password + ), FPara.connStr) = null) umessage.Info = 1; _translator.Serialize(ms, umessage); byte d = new bytems.Length; ms.Seek(0, SeekOrigin.Begin); ms.Read(d, 0, d.Length); sc.Send(d); else umessage.Info = 2; _translator.Serialize(ms, umessage); byte d = new bytems.Length; ms.Seek(0, SeekOrigin.Begin); ms.Read(d, 0, d.Length); sc.Send(d); #endregion usdr.Close(); #endregion如果发现用户发送的是登录信息,就根据登录信息中的用户名和密码判断是否存在用户,密码是否正确,成功后再查询出用户的好友信息并且赋值给FriendStruct,再将信息返回给客户端: #region 处理用户登录信息 else if (info = 1)/分辨出用户发送的是登录信息 string Accounts = umessage.Accounts; string Password = umessage.Password; SqlDataReader usdr = FPara.SqlReader(select * from TCP_UserInfo where UserAccount= + Accounts + and UserPassword=+Password+, FPara.connStr); if (usdr != null) if (usdr.Read() string uid=usdrUserID.ToString(); umessage.Fg = usdrUserFav.ToString(); usdr.Close(); SqlDataAdapter sdr = new SqlDataAdapter(select * from TCP_UserInfo join TCP_FriendInfo on TCP_FriendInfo.UserID= + uid + and TCP_UserInfo.UserID=TCP_FriendInfo.FriendID, FPara.connStr); DataSet ds = new DataSet(); sdr.Fill(ds,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 函数的奇偶性的说课稿
- 上市公司员工购房合同范本
- 转口贸易合同中运输条款
- 办公大楼浮雕施工合同
- 物业公司财务内控手册
- 城市公园绿化招投标报名表
- 活动摄像租赁简易合同
- 餐饮KTV音响系统设备协议
- 航运服务招投标专用合同条款
- 体育馆消防工程合同
- 2023年北京市重点校初三(上)期末历史试题汇编:第一次工业革命
- 《最后一片叶子》课件
- 2024年小轿车买卖合同标准版本(三篇)
- 八年级生物中考备考计划
- 2024-2030年全球及中国湿巾和卫生纸行业市场现状供需分析及市场深度研究发展前景及规划可行性分析研究报告
- 公务员2019年国考《申论》真题及答案(省级)
- 2024年会计专业考试初级会计实务试卷与参考答案
- 职业技术学院材料工程技术专业调研报告
- 五年级阅读《概括题专项训练》
- 《算法设计与分析基础》(Python语言描述) 课件 第9章NP完全问题
- 2024-2030年中国辐照加速器行业运营态势及未来前景预测研究报告
评论
0/150
提交评论