第19章网络编程函数库_第1页
第19章网络编程函数库_第2页
第19章网络编程函数库_第3页
第19章网络编程函数库_第4页
第19章网络编程函数库_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第19章网络编程函数库网络应用中有许多建立在应用层的协议,这些协议提供了常用的HTTP、FTP、TELNET、EMAIL和即时通信服务。在Linux系统上设计这些网络应用可通过查阅RFC(RequestForComments)文档获取相关协议的细节,再用Socket编程实现这些细节以组成一个网络应用程序。但如果对这些应用没有特殊的性能或功能要求,可使用现有的函数库来构建所需要的网络应用,所有常见网络应用在Linux系统上都有对应的函数库。本章将介绍其中最常用的几个函数库。19.1HTTP与FTP函数库超文本传输协议(HyperTextTransferProtocol,HTTP)是Internet上应用最为广泛的一种网络协议。所有的Web网站都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。HTTP协议以TCP为基础,是Web客户端与WWW服务器之间的应答标准。客户端是终端用户,例如Linux系统上的FireFox浏览器。服务器端是网站,Apache是Linux系统上典型的WWW服务器。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求,通常称之为用户代理(Useragent)。应答的服务器上存储着一些资源,例如HTML文件和图像。通常称这个应答服务器为源服务器(Originserver)。在用户代理和源服务器中间可能存在多个中间层,例如代理、网关和隧道(Tunnels)。19.1HTTP与FTP函数库文件传输协议(FileTransferProtocol,FTP)是进行文件传输的一套标准协议,属于TCP/IP协议中的一部分。FTP服务一般运行在20和21两个端口。其中端口20用于传输数据流,端口21用于传输控制流。FTP有两种使用模式:主动传输模式和被动传输模式。主动传输模式安全性更高,要求客户端和服务器端同时打开并且监听一个端口以建立连接。但客户端的防火墙会阻碍主动传输模式,所以创立了被动传输模式。被动传输模式比较简单,只要求服务器监听相应端口的进程,这样就可以绕过客户端防火墙的问题。统一资源定位符(Uniform/UniversalResourceLocator,URL)也被称为网页地址,是Internet上标准的资源的地址(Address)。在Linux系统中实现这两种服务的函数库有很多,本节将介绍其中最流行的libcurl库,演示使用libcurl库中常用函数建立简单客户端程序的方法。19.1.1libcurl函数库简介libcurl是一个为网络客户端提供数据传输功能的函数库,它支持HTTP、HTTPS、FTP、FTPS、SCP、SFTP、TFTP、DICT、TELNET、LDAP或FILE等协议,支持各种SSL安全认证。使用libcurl函数库设计客户端程序的优点是,功能强大,不需要了解各种协议的细节,程序简单易行。libcurl是开源项目,可在其官方网站获得源代码并安装。在基于libcurl的程序里,主要采用回调函数(callbackfunction)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数。当满足条件时,libcurl将调用用户的回调函数实现特定功能。libcurl的工作模式有两种,一种称为简单接口,这种模式下可进行同步、直接、快速的文件传输,适用于大多数情况;另一种称为多线程接口,多线程接口可生成多个连接线程以异步方式进行文件传输。使用简单接口模式的libcurl程序的工作流程如后图所示。19.1.1libcurl函数库简介19.1.2libcurl中的主要函数与libcurl相关的函数被包含在头文件“curl/curl.h”中。使用libcurl前首先要对libcurl进行初始化,可通过curl_global_init()函数实现,它的一般形式是:CURLcodecurl_global_init(longflags);该函数只能使用一次,如果在调用curl_easy_init()函数前没有调用curl_global_init()函数,那么curl_easy_init()函数会自动调用curl_global_init()函数。参数flags用于指定初始化状态,它的可选范围是一组枚举变量,如表所示。枚举成员名称说

明CURL_GLOBAL_ALL初始化所有可能的调用CURL_GLOBAL_SSL初始化支持安全套接字层的调用CURL_GLOBAL_WIN32初始化WIN32套接字库CURL_GLOBAL_NOTHING没有额外的初始化要求19.1.2libcurl中的主要函数在结束libcurl使用的时候,可使用curl_global_init()函数清理内存,该函数的作用类似于close()系统调用。对libcurl初始化后,可使用curl_easy_init()函数获得一个CURL操作符,这个操作符的作用与文件操作符非常相似,程序中可通过CURL操作符访问相应的网络资源。该函数的一般形式是:CURL*curl_easy_init();在CURL操作符使用完毕,同样需要对其内存进行清理,可使用函数curl_easy_cleanup()完成,它的一般形式是:voidcurl_easy_cleanup(CURL*handle);19.1.2libcurl中的主要函数进行数据传输前必须告诉libcurl如何工作,使用curl_easy_setopt()函数可指定libcurl的工作方式,或者在程序运行中改变libcurl工作方式。它的一般形式是:CURLcodecurl_easy_setopt(CURL*handle,CURLoptionoption,parameter);该函数的第一个参数是CURL标识符,第二个参数是CURLoption类型的选项,第三个参数parameter既可以是函数的指针,又可以是某个对象的指针,也可以是long型的变量,它的类型取决于第二个参数的定义。CURLoption类型中关于HTTP和FTP的选项如后表所示。19.1.2libcurl中的主要函数选

项说

明CURLOPT_URL设置要访问的URLCURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA回调函数原型为:size_tfunction(void*ptr,size_tsize,size_tnmemb,void*stream);函数将在libcurl接收到数据后被调用,因此函数多做数据保存的功能,如处理下载文件。CURLOPT_WRITEDATA用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA回调函数原型为:size_tfunction(void*ptr,size_tsize,size_tnmemb,void*stream);libcurl一旦接收到http头部数据后将调用该函数。CURLOPT_WRITEDATA传递指针给libcurl,该指针表明CURLOPT_HEADERFUNCTION函数的stream指针的来源CURLOPT_READFUNCTION,CURLOPT_READDATAlibCurl需要读取数据传递给远程主机时将调用CURLOPT_READFUNCTION指定的函数,函数原型是:size_tfunction(void*ptr,size_tsize,size_tnmemb,void*stream);CURLOPT_READDATA表明CURLOPT_READFUNCTION函数原型中的stream指针来源CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA跟数据传输进度相关的参数。CURLOPT_PROGRESSFUNCTION指定的函数正常情况下每秒被libcurl调用一次,为了使CURLOPT_PROGRESSFUNCTION被调用,CURLOPT_NOPROGRESS必须被设置为false,CURLOPT_PROGRESSDATA指定的参数将作为CURLOPT_PROGRESSFUNCTION指定函数的第一个参数CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUTCURLOPT_TIMEOUT用于设置传输时间CURLOPT_CONNECTIONTIMEOUT设置连接等待时间CURLOPT_FOLLOWLOCATION设置重定位URL19.1.2libcurl中的主要函数设置好工作方式后,可使用curl_easy_perform()函数执行相关操作。该函数的一般形式是:CURLcodecurl_easy_perform(CURL*handle);函数执行后,就会根据curl_easy_setopt()函数指定的工作方式开始工作。如果执行成功,返回值为0,否则返回一个错误代码。常见的错误代码如表所示。代

码说

明CURLE_OK任务已完成CURLE_UNSUPPORTED_PROTOCOL不支持由URL的头部指定的协议CURLE_COULDNT_CONNECT不能连接到远程主机或者代理CURLE_REMOTE_ACCESS_DENIED访问被拒绝CURLE_HTTP_RETURNED_ERRORHttp返回错误CURLE_READ_ERROR读取本地文件错误19.1.3使用libcurl实现简单的HTTP访问本例将使用简单接口模式设计一个HTTP访问的应用程序,通过网络获得的HTML文件(超文本文件格式文件,HTTP服务所使用的标准文件格式),并将该文件保存到本地。(19_1_3.c)编译包含libcurl库程序时需要加入编译指令-lcurl,见本书9.6.3节所示。在程序的开始部分定义了一个回调函数,回调函数的参数是libcurl所规定的。该程序的执行参数有两个,第一个是URL,第二个是本地文件路径。将libcurl的工作方式设置为CURLOPT_URL后,第一个参数被传递给libcurl作为要访问的地址。然后设置CURLOPT_WRITEFUNCTION,将回调函数的名称传递给libcurl。这样,在执行curl_easy_perform()完成后,回调函数将从网络上获得的数据写入本地文件。19.2SMTP、POP与IMAP函数库IMAP、POP与SMTP是常用的3种电子邮件协议。SMTP称为简单Mail传输协议(SimpleMailTransferProtocal),目标是向用户提供高效、可靠的邮件传输。SMTP的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器。SMTP监听25号端口,用于接收用户的Mail请求,并与远端Mail服务器建立SMTP连接。POP的是邮局协议(PostOfficeProtocol),用于电子邮件的接收,它使用TCP的110端口,现在常用的是第三版,所以简称为POP3。POP3仍采用客户端与服务器工作模式。当客户机需要服务时,客户端的软件(OutlookExpress或FoxMail)将与POP3服务器建立TCP连接,此后要经过POP3协议的3种工作状态,首先是认证过程,确认客户机提供的用户名和密码。在认证通过后便转入处理状态,在此状态下用户可收取自己的邮件或做邮件的删除。在完成响应的操作后客户机便发出quit命令,此后进入更新状态,将做删除标记的邮件从服务器端删除掉。到此为止整个POP过程完成。19.2SMTP、POP与IMAP函数库IMAP(InternetMessageAccessProtocol)是通过Internet获取邮件信息的一种协议。IMAP像POP那样提供了方便的邮件下载服务,让用户能进行离线阅读,但IMAP能完成的却远远不止这些。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才做出是否下载的决定。本节将介绍Linux系统中用于实现电子邮件客户端的函数库。19.2.1使用libESMTP函数库实现电子邮件发送libESMTP函数库是Linux系统上最常用的SMTP协议库,很多电子邮件客户端的邮件传送功能都是建立在该库的基础上,有的甚至直接借用其实现SMTP协议细节的代码。要使用该函数库可在其官方站点“”上获得源文件进行编译,或者在Linux终端内输入下列命令:apt-getinstalllibesmtp6libesmtp-dev无验证方式通过SMTP服务器发送邮件的程序。(19_2_1.c)19.2.1使用libESMTP函数库实现电子邮件发送邮件的内容被定义在文件mail.eml文件中,可以用下例的形式编辑一个邮件:[quote]Return-Path:<[email]test@localhost[/email]>

//回复地址Subject:LibESMTP测试邮件MIME-Version:1.0

//定义邮件的版本Message-Id:<[email]test@localhost[/email]>

//目的地地址Content-Type:text/plain;

//定义邮件类型

charset=iso-8859-1

//定义字符编码类型Content-Transfer-Encoding:7bit

//定义传送指令长度邮件邮件内容开始,...邮件内容结束---本例使用Linux系统中自带的SMTP服务器传送邮件,测试前需要确定SMTP服务器已开启,并建立一个test@localhost邮箱。另外需要将SMTP发送验证设为关闭,也不要开启SSL连接模式。程序的编译参数为“`pkg-config--cflags–libsesmtp`”。19.2.2使用libspopc函数库实现POP访问libspopc函数库是一个开源项目,该项目提供了简单的POP协议接口。可在libspopc的官方网站“”上获得函数库源文件进行编译,Linux系统中安装libspopc的命令为:yuminstalllibspopclibspopc-devel //YUM提供的可能不是该软件最新版本该函数库提供了两类访问POP服务器的函数,一类是高层函数,另一类是低层函数。下例将演示如何以高层函数访问POP服务器。(19_2_2.c)本例中定义了emaillist结构体用于保存邮件列表的信息,该结构体所占用的内存是根据邮件数量动态分配的。接收邮件的过程极为简单,首先定义popsession结构指针,用户输入了服务器地址、用户名和密码后通过popbegin()函数创建一个POP会话,popsession结构指针里保存相应会话的标识符。然后用popmsgsize()函数获得每个邮件的长度,用popmsguid()函数获得邮件的编码,用popgethead()函数获得邮件的标题,用popgetmsg()函数获得邮件内容。在连接完成后,使用popend()函数终止会话。最后,使用libspopc_clean()进行清理。程序编译时需要加入编译参数“`pkg-config--cflags--libslibspopc`”,如果libspopc库是通过源文件编译而来的,则需要在“/usr/lib/pkgconfig”路径中参照其它库配置“libspopc.pc”文件。19.2.3使用mailutils函数库实现IMAP访问IMAP的实现比POP要复杂许多,与IMAP服务器建立连接后,可直接通过会话管理邮箱中的文件。常用的IMAP函数库为华盛顿大学提供的UW-IMAP和GNU项目中的mailutils函数库,两者都能支持几乎所有的电子邮件协议,包括SMTP和POP。UW-IMAP倾向于电子邮件服务器程序的设计,mailutils函数库更倾向于邮件客户端开发。mailutils没有对应Linux系统的安装包,必须在GNU官方网站上下载源代码编译安装,下载地址为,源代码中含有详细的IMAP访问实现范例。访问IMAP服务器的工作流程与POP非常相似,只需要用对应函数替代上例中函数即可。IMAP函数在头文件mailutils/mailutils.h中,如表所示。函

名说

明intimap4_create(imap4_t*);创建IMAP会话intimap4_open(imap4_t,constchar*hostname,unsignedintport,intflags);建立IMAP连接intimap4d_set_timeout(imap4_t,unsignedintseconds);设置连接超时时间intimap4_append(imap4_t);设置IMAP路径intimap4_capability(imap4_t);设置IMAP容量intimap4_create_mailbox(imap4_t,constchar*mbox);创建IMAP文件夹intimap4_check(imap4_t);检查邮件intimap4_close(imap4_t);关闭IMAP连接19.3即时通信函数库即时通信软件(IM)是一种用于网络间文本消息传递的程序,又称为聊天软件。自诞生以来,逐渐成为网络上最重要的通信工具,并向着多元化方向发展。目前,主流的即时通信软件不但能提供语音和视频通信,而且集成了电子邮件、游戏、电子商务、办公协作等功能,成为了综合化信息平台。因为提供即时通信服务的服务商没有统一的标准,所以即时通信软件的协议各不相同,甚至大多数协议都不对外开放。常见的协议如下。ICQ:世界上出现最早、使用最广泛的即时通信工具。IRC:一种开放的文本交流平台。MSN:微软公司开发的即时通信工具。QQ:中国腾讯公司开发的即时通信工具。Yahoo!IM:雅虎公司开发的即时通信工具。但是在Linux系统中,即时通信软件各自为政的时代已经结束,大多数软件都能支持多个即时通信协议。其中最著名的为Pidgin,它支持几乎所有流行的即时通信协议,各种协议以插件的形式存在,因而可以方便地增加新协议的支持。Pidgin提供了libpurple函数库,Pidgin自身即建立在该函数库之上。现在Pidgin和libpurple已作为GNOME桌面环境的一部分发行。19.3.1libpurple函数库简介libpurple函数库提供了一种进行即时通信的公共机制,所有的即时通信协议都可以作为其一部分来运行。它支持多个操作系统,包括Linux系统、Windows系统和其它类UNIX系统,例如SCO-UNIX、BSD和AmigaOS。函数库本身支持NSS,为客户端和服务器之间加密通信的协定提供基础。除此之外,使用者可以安装插件来得到更多功能,每一种通信协议都作为插件装入libpurple函数库。libpurple函数库包含了一般即时通信软件的功能,例如网络聊天、联系人信息管理、文件传输和聊天记录查询功能。另外,该函数库支持GTK+,可直接生成具有图形界面的即时通信软件。与当前Linux系统上另一个流行的多协议即时通信函数库Telepathy相比,libpurple所支持的协议更为丰富,运行效率更高。但libpurple在语音和视频通信方面的进展要比Telepathy慢,后者已开发出成熟的语音和视频通信函数库。运行GNOME桌面的Linux系统通常已包含该函数库,如果需要下载源代码,可登录其官方站点获得。源代码包中提供了该函数库的详细文档,以及多个示例程序。19.3.2即时通信软件工作机制大部分即时通信软件的工作机制是相同的,因此才会出现libpurple这样几乎能够支持所有即时通信软件。即时通信软件的工作机制如图所示。19.3.2即时通信软件工作机制即时通信服务商在网络上架设一台服务器,这台服务器上存放有所有用户的信息。用户与服务器连接的过程称之为用户登录,用于登录的步骤如下:(1)用户通过网络地址向服务器发出连接请求。(2)服务器接收请求,与用户建立连接,通常是TCP连接。(3)服务器将自己支持的协议版本发送给用户。(4)用户收到协议版本后,如果具有相同的协议版本,就传送一个协议匹配指令和匹配协议中最新的版本号,否则传送协议不匹配指令。(5)服务器收到用户答复,如果是协议不匹配,通常会传送一个要求升级的消息,然后断开连接。如果协议匹配,那么将按照指定的协议与用户进行通信。(6)服务器向用户发送要求用户ID与密码的指令。(7)用户将用户ID与密码通过加密方式传送给服务器(通常是MD5算法)。(8)服务器将用户ID与密码信息进行解密,并与自身所保存的信息进行比较。如果信息不匹配,服务器发出身份不符消息,然后断开与用户的连接。如果信息匹配,服务器记录用户的网络地址,并将其它相关用户的状态传送回去。(9)用户收到服务器返回的身份正确消息和其它用户状态后,断开与服务器的TCP连接,以减轻服务器负担。然后每隔一定周期的时间,将自身状态通过UDP报告给服务器。如果用户要结束连接,那么也会在程序退出之前向服务器发送离线消息。如果服务器超过一定时间没有收到用户信息,那么将认为用于已非正常退出。19.3.2即时通信软件工作机制用户之间进行消息传递一般情况下并不需要通过服务器中转,服务器会在一定周期内更新一次用户的联系人列表中的联系人信息。这其中包括有联系人的网络地址,用户可以直接通过地址向联系人发出连接请求,这样双方即能进行通信。有的即时通信服务提供了离线消息功能,这种功能是通过服务器中转的方式实现的。19.3.3使用libpurple函数库接入服务器下面是一个libpurple函数库中标准示例改编而来的程序,该程序假设用户已经通过Pidgin或其它方法设配置了即时通信账户信息。(19_3_3.c)1.预处理在该示例的预处理部分,定义了程序中使用的头文件、常量、宏和数据结构。预处理部分首先定义了常量CUSTOM_USER_DIRECTORY、CUSTOM_PLUGIN_PATH和PLUGIN_SAVE_PREF,程序的其它部分通过这些常量获得相应目录的路径。常量UI_ID是用户接口ID,通常为应用程序的名字。libpurple的文件读写操作通过GLib库实现,为了使整个程序能获得统一的属性,预处理部分定义了宏PURPLE_GLIB_READ_COND和PURPLE_GLIB_WRITE_COND。这两个宏分别是读取和写入的属性标志,其后是用按位或运算得到的相关属性值。结构体_PurpleGLibIOClosure是根据GLib库对回调函数的要求定义的参数数据类型,其中的3个成员分别为函数名、返回结果和数据参数。19.3.3使用libpurple函数库接入服务器2.清除函数清除函数的设计思想与面向对象语言中的析构函数相似,负责在程序退出时清除动态分配的内存。函数的参数为gpointer类型,可以用于处理任何类型的数据。当某一数据类型不再被使用时,该函数将调用g_free()函数释放动态分配的内存。g_free()函数与free()函数类似,只是g_free()函数增加了对GLib库定义的复合数据结构的支持。3.调用GLib输入输出接口调用GLib输入输出接口函数是一个回调函数,其中3个形式参数分别是GLib输入输出通道指针、GLib输入输出条件和数据指针。该函数的作用是在需要时打开GLib输入输出通道,读取或写入数据。函数中创建了一个libpurple输入输出终止符,该终止符指针指向了函数的数据指针。然后判断参数中的GLib输入输出条件是读取还是写入,根据此条件设置libpurple输入条件。然后,使用数据指针中定义的回调函数执行输入输出操作。19.3.3使用libpurple函数库接入服务器4.加入一个GLib输入接口在程序开始执行时,并没有定义GLib输入接口。该接口可用于网络、数据库和文件的读写操作。函数中首先创建了libpurple输入输出终止符,然后创建了一个GLib通道。最后,为了让通道能对新增写入的消息作出反应,使用g_io_add_watch_full()函数设置通道中的回调函数。GLib通道与D-Bus中的总线非常相似,都能够在得到消息时主动处理。5.定义GLib事件循环GLib事件循环被定义在PurpleEventLoopUiOps类型中,并作为全局变量供程序中其它位置使用。源代码中创建了一个静态PurpleEventLoopUiOps类型全局变量glib_eventloops。创建时,某些成员必须在GLib函数库版本大于2.14.0的情况下才有效,因此用宏GLIB_CHECK_VERSION()检查GLib版本。6.定义会话时的输出会话时输出函数有6个参数,分别为会话标识符、好友ID、昵称、消息、消息类型和发送时间。该函数的作用是将这些信息输出到终端。函数中使用了与运算判断一个字符串是否为空,如表达式alias&&*alias所示。该表达式的意义是,指针alias指向的位置不为NULL,并且*alias指向的内存中字符串不为“\0”,表达式的结果才为真。7.定义会话UI选项会话的UI选择定义在PurpleConversationUiOps类型中,用于决定打开的聊天窗口样式。代码中创建了静态PurpleConversationUiOps类型全局变量null_conv_uiops。因为本程序的运行目标为终端,所以将大部分UI选项设置为NULL。19.3.3使用libpurple函数库接入服务器8.初始化用户接口初始化用户接口通过函数null_ui_init()实现,源代码如下:staticvoidnull_ui_init(void)

//初始化用户接口{

purple_conversations_set_ui_ops(&null_conv_uiops);

//使用会话UI选项初始化用户接口}函数中只调用了purple_conversations_set_ui_ops()函数初始化用户接口,参数为上一步所定义的全局变量null_conv_uiops。9.定义核心用户接口选项staticPurpleCoreUiOpsnull_core_uiops=

//定义核心用户接口选项{

NULL,NULL,null_ui_init,NULL};19.3.3使用libpurple函数库接入服务器10.初始化libpurple在使用libpurple前,首先要对libpurple库进行初始化。初始化的内容包括设置各种目录的路径、读取账户信息和连接到即时通信服务器。代码中首先调用purple_util_set_user_dir()函数设置用户目录,然后调用purple_debug_set_enabled()函数设置调试状态,调用purple_core_set_ui_ops()函数设置核心用户接口选项。以及调用purple_eventloop_set_ui_ops()函数设置GLib事件循环,调用purple_plugins_add_search_path()函数设置搜索插件路径。这些函数的参数都是在程序前面定义的常量和全局变量。UI_ID常量中保存的是用户接口ID,purple_core_init()函数以用户接口ID为参数对libpurple核心进行初始化。如果初始化成功,libpurple库已通过网络连接到IM服务器。然后可以用purple_blist_load()函数和purple_prefs_load()函数下载联系人列表,用purple_plugins_load_s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论