欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    网络编程实用教程第二版课件.ppt

    • 资源ID:1592106       资源大小:1.53MB        全文页数:100页
    • 资源格式: PPT        下载积分:16金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要16金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    网络编程实用教程第二版课件.ppt

    网络编程实用教程第二版,2.1.1 问题的提出 站在应用程序实现的角度,应用程序如何方便地使用协议栈软件进行通信呢? 如果能在应用程序与协议栈软件之间提供一个软件接口,就可以方便客户与服务器软件的编程。,2.1 UNIX套接字网络编程接口的产生与发展,套接字应用程序编程接口是网络应用程序通过网络协议栈进行通信时所使用的接口,即应用程序与协议栈软件之间的接口,简称套接字编程接口(Socket API)。 它定义了应用程序与协议栈软件进行交互时可以使用的一组操作,决定了应用程序使用协议栈的方式、应用程序所能实现的功能、以及开发具有这些功能的程序的难度。,加州大学伯克利(Berkley)分校开发并推广了一个包括TCP/IP互联协议的UNIX,称为BSD UNIX(Berkeley Software Distribution UNIX)操作系统,套接字编程接口是这个操作系统的一个部分。 后来的许多操作系统并没有另外搞一套其它的编程接口,而是选择了对于套接字编程接口的支持。 由于这个套接字规范最早是由Berkeley大学开发的,一般将它称为Berkeley Sockets规范。,2.1.2 套接字编程接口的起源与应用,微软公司以UNIX操作系统的Berkeley Sockets规范为范例,定义了Windows Socktes规范,全面继承了套接字网络编程接口。详细内容将在第三章介绍。Linux操作系统中的套接字网络编程接口几乎与UNIX操作系统的套接字网络编程接口一样。本章着重介绍三大操作系统的套接字网络编程接口的共性问题。,2.1.3 套接字编程接口在Windows和Linux操作系统中得到继承和发展,要想实现套接字编程接口,可以采用两种实现方式, 一种是在操作系统的内核中增加相应的软件来实现, 一种是通过开发操作系统之外的函数库来实现。,2.1.4 套接字编程接口的两种实现方式,UNIX操作系统对文件和所有其它的输入/输出设备采用一种统一的的操作模式,就是“打开-读-写-关闭”(open - read - write - close)的I/O模式。 当TCP/IP协议被集成到UNIX内核中的时候,相当于在UNIX系统中引入了一种新型的I/O操作,就是应用程序通过网络协议栈来交换数据。,2.1.5 套接字通信与UNIX操作系统的输入/输出,在UNIX系统的实现中,套接字是完全与其他I/O集成在一起的。操作系统和应用程序都将套接字编程接口也看作一种输入/输出机制。 但是,用户进程与网络协议的交互作用实际要比用户进程与传统的I/O设备相互作用要复杂得多。,其次,使用套接字的应用程序必须说明许多细节。仅仅提供open、read、write、close四个过程远远不够。为避免单个套接字函数参数过多,套接字编程接口的设计者定义了多个函数。,2.2 套接字编程的基本概念,套接口是对网络中不同主机上应用进程之间进行双向通信的端点的抽象,一个套接口就是网络上进程通信的一端,提供了应用层进程利用网络协议栈交换数据的机制。,图2.1 电插座与电话插座的作用,2.2.1 什么是套接字(SOCKET),我们应当从多个层面来理解套接字这个概念的内涵。 从套接字所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议栈进行通信的接口,是应用程序与网络协议栈进行交互的接口。,图2.2 应用进程、套接口、网络协议栈及操作系统的关系,从实现的角度来讲,非常复杂。套接字是一个复杂的软件机构,包含了一定的数据结构,包含许多选项,由操作系统内核管理。 从使用的角度来讲,非常简单。对于套接字的操作形成了一种网络应用程序的编程接口(API)。 本书把这一套操作套接字的编程接口函数称作套接字编程接口,套接字是它的操作对象。 总之,套接字是网络通信的基石。,2.2.2 套接字的特点1通信域 接字存在于通信域中,通信域是为了处理一般的进程通过套接字通信而引入的一种抽象概念,套接字通常只和同一域中的套接字交换数据。 如果数据交换要穿越域的边界,就一定要执行某种解释程序。 现在,仅仅针对Internet域,并且使用Internet协议族(即TCP/IP协议族)来通信。,2套接字具有三种类型 每一个正被使用的套接字都有它确定的类型,只有相同类型的套接字才能相互通信。(1)数据报套接字(Datagram SOCKET) 数据报套接字提供无连接的不保证可靠的独立的数据报传输服务。在Internet通信域中,数据报套接字使用UDP数据报协议形成的进程间通路,具有UDP协议为上层所提供的服务的所有特点。,图2.3 在Internet通信域中,数据报套接字基于UDP协议,(2)流式套接字(Stream SOCKET) 流式套接字提供双向的、有序的、无重复的、无记录边界的可靠的数据流传输服务。在Internet通信域中,流式套接字使用TCP协议形成的进程间通路,具有TCP协议为上层所提供的服务的所有特点,在使用流式套接字传输数据之前,必须在数据的发送端和接收端之间建立连接,如图2.4所示。,图2.4 在Internet通信域中,流式套接字基于TCP协议,(3)原始式套接字(RAW SOCKET),原始式套接字允许对较低层次的协议,如IP、ICMP直接访问,用于检验新的协议的实现。,3套接字由应用层的通信进程创建,并为其服务 就是说,每一个套接字都有一个相关的应用进程,操作该套接字的代码是该进程的组成部分。,4使用确定的IP地址和传输层端口号,往往在生成套接字的描述符后,要将套接字与计算机上的特定的IP地址和传输层端口号相关联,这个过程称为绑定。 一个套接口要使用一个确定的三元组网络地址信息,才能使它在网络中唯一地被标识。,(1)不管是采用对等模式或者客户机/服务器模式,通信双方的应用程序都需要开发。(2)双方所交换数据的结构和交换数据的顺序有特定的要求,不符合现在成熟的应用层协议,甚至需要自己去开发应用层协议,自己设计最适合的数据结构和信息交换规程。,2.2.3 套接字的应用场合,2.2.4 套接字使用的数据类型和相关的问题1三种表示套接字地址的结构 在套接字编程接口中,专门定义了三种结构型的数据类型,用来存储协议相关的网络地址,在套接字编程接口的函数调用中要用到它们。,(1)sockaddr结构,针对各种通信域的套接字,存储它们的地址信息。struct sockaddr unsigned short sa_family; / 地址家族char sa_data; / 协议地址,(2)sockaddr_in结构,专门针对Internet通信域,存储套接字相关的网络地址信息,例如IP地址,传输层端口号等信息。struct sockaddr_in short int sin_family; / 地址家族unsigned short int sin_port; / 端口号struct in_addr sin_addr; / IP 地址unsigned char sin_zero8; / 全为0,(3)in_addr结构,专门用来存储 IP地址。Struct in_addr Unsigned long s_addrl;,(4)这些数据结构的一般用法: 首先,定义一个Sockaddr_in的结构实例,并将它清零。比如:struct sockaddr_in myad;memset(,然后,为这个结构赋值,比如:myad.sin_family=AF_INET; myad.sin_port=htons(8080); myad.sin_addr.s_addr=htonl(INADDR-ANY);,第三步:在函数调用中使用时,将这个结构强制转换为sockaddr类型。如:accept(listenfd,(sockaddr*)(,2本机字节顺序和网络字节顺序 在具体计算机中的多字节数据的存储顺序,称为本机字节顺序。 多字节数据在网络协议报头中的存储顺序,称为网络字节顺序。,网络应用程序要在不同的计算机中运行,本机字节顺序是不同的,但是,网络字节顺序是一定的。 所以,应用程序在编程的时候,在把IP地址和端口号装入套接字的时候,应当把它们从本机字节顺序转换为网络字节顺序;相反,在本机输出时,应将它们从网络字节顺序转换为本机字节顺序。,套接字编程接口特为解决这个问题设置了四个函数:htons() 短整数本机顺序转换为网络顺序,用于端口号。htonl() 长整数本机顺序转换为网络顺序,用于IP地址。,ntohs() 短整数网络顺序转换为本机顺序,用于端口号。ntohl() 长整数网络顺序转化为本机顺序,用于IP地址。 这四个函数将被转换的数值作为函数的参数,函数返回值是转换后的结果。,3点分十进制的IP地址的转换 在因特网中,IP地址常常用点分十进制的表示方法,但在套接字中,IP地址是无符号的长整型数,套接字编程接口设置了两个函数,专门用于两种形式的IP地址的转换。,(1)inet-addr函数,unsigned long inet-addr( const char* cp)入口参数cp:点分十进制形式的IP地址。返回值: 网络字节顺序的IP地址,是无符号的长整数,,(2)inet_ntoa函数,char* inet_ntoa(struct in_addr in)入口参数in:包含长整型IP地址的 in_addr 结构变量,返回值: 指向点分十进制IP地址的字符串的指针。,通常,我们使用域名来标识站点,可以将文字型的主机域名直接转换成IP地址,struct hostent* gethodtbyname( const char* name);入口参数:是站点的主机域名字符串,返回值: 是指向hostent 结构的指针,hostent结构包含主机名,主机别名数组,返回地址的类型(一般是AF-INET),地址长度的字节数,已符合网络字节顺序的主机网络地址等。,4域名服务,2.3 面向连接的套接字编程2.3.1 套接字的工作过程,2.3.2 UNIX套接字编程接口的系统调用1创建套接字SOCKET()SOCKET过程创建一个套接字并返回一个整型描述符:int SOCKET( int Protofamily, int Type, int Protocol);,2绑定套接字到指定的地址 BIND(),int BIND( int Sockfd, struct sockaddr* My_addr, int Addrlen);,3启动监听Listen(),int LISTEN( int Sockfd, int Queuesize);,举例:LISTEN(Sockfe, 10);,图2.6 监听套接字使用缓冲区接纳多个客户端的连接请求,4接收连接请求ACCEPT()int ACCEPT(int Sockfd, struct sockaddr* Addr, int* addrlen);举例:int clientfd; / 定义响应套接字描述符变量int addrler=sizeof(sockaddr); / 获得套接字地址结构长度。struct sockaddr_in cltsockaddr; / 定义用于返回客户端地址的结构。clientfd=ACCEPT(listenfd, (sockaddr* )( / 接收客户连接请求,5请求建立连接CONNECT()int CONNECT( int Sockfd, struct sockaddr* Service_addr, int Addrlen);举例:if (CONNECT(sockfd, (struct sockaddr*)(&serv_addr),sizeof(struct sockaddr)0) 报错,并退出 ,6读/写套接字READ()和WRITE()int READ( int sockfd, void* buffer, int len );int WRITE( int sockfd, void* buffer, int len ),7向套接字发送 SEND() 和从套接字接收 RECV(),int SEND( int sockfd, char* buf, int len, int flags );int RECV( int sockfd, char* buf, int len, int flags );,8关闭套接字CLOSE(),int CLOSE( int sockfd );,2.3.3 面向连接的套接字编程实例1实例的功能 服务器对来访的客户计数,并向客户报告这个计数值。 客户建立与服务器的一个连接并等待它的输出。 每当连接请求到达时,服务器生成一个可打印的ASCII串信息,将它在连接上发回,然后关闭连接。 客户显示收到的信息,然后退出。,例如,对于服务器接收的第10次客户连接请求,该客户将收到并打印如下信息:This server has been contacted 10 times.,2实例程序的命令行参数 实例是UNIX环境下的C程序,客户和服务器程序在编译后,均以命令行的方式执行。 服务器程序执行时可以带一个命令行参数,是用来接受请求的监听套接字的协议端口号。这个参数是可选的。如果不指定端口号,代码将使用程序内定的缺省端口号5188。,客户程序执行时可以带两个命令行参数:一个是服务器所在计算机的主机名,另一个是服务器监听的协议端口号。 这两个参数都是可选的。 如果没有指定协议端口号,客户使用程序内定的缺省值5188。 如果一个参数也没有,客户使用缺省端口和主机名localhost,localhost是映射到客户所运行的计算机的一个别名。 允许客户与本地机上的服务器通信,对调试是很有用的。,3客户程序代码/*-* 程序: client.c* 目的: 创建一个套接字,通过网络连接一个服务器,并打印来自服务器的信息* 语法: client host port * host - 运行服务器的计算机的名字* port - 服务器监听套接字所用协议端口号* 注意:两个参数都是可选的。如果未指定主机名,客户使用localhost;如果未指定端口号, * 客户将使用PROTOPORT中给定的缺省协议端口号*-*/,#include #include /* UNIX下,套接字的相关包含文件。*/#include #include #include #include #include #define PROTOPORT 5188 /*缺省协议端口号*/extern int errno;char localhost = “localhost”; /*缺省主机名*/,main(argc,argv)int argc;char *argv;struct hostent *ptrh; /* 指向主机列表中一个条目的指针 */struct sockaddr_in servaddr; /* 存放服务器端网络地址的结构 */intsockfd; /* 客户端的套接字描述符 */intport; /* 服务器端套接字协议端口号*/char* host; /* 服务器主机名指针 */int n; /* 读取的字符数 */char buf1000 ; /* 缓冲区,接收服务器发来的数据 */,memset(char*) /* 否则,使用缺省端口号 */if (port0) /* 如果端口号是合法的数值,就将它装入网络地址结构 */,servaddr.sin_port = htons(u_short)port);else /* 否则,打印错误信息并退出*/fprintf(stderr,”bad port number %sn”,argv2);exit(1);/* 检查主机参数并指定主机名 */if(argc1)host = argv1; /* 如果指定了主机名参数,就使用它 */elsehost = localhost; /* 否则,使用缺省值 */,/* 将主机名转换成相应的IP地址并复制到servaddr 结构中 */ptrh = gethostbyname( host ); /* 从服务器主机名得到相应的IP地址 */if ( (char *)ptrh = null ) /* 检查主机名的有效性,无效则退出 */fprintf( stderr, ”invalid host: %sn”, host );exit(1);memcpy(,/* 创建一个套接字*/sockfd = SOCKET(AF_INET, SOCK_STREAM, 0);if (sockfd 0) fprintf(stderr, ”socket creation failedn” );exit(1);/* 请求连接到服务器 */if (connect( sockfd, (struct sockaddr *),/* 从套接字反复读数据,并输出到用户屏幕上 */n = recv(sockfd , buf, sizeof( buf ), 0 );while ( n 0) write(1,buf, n);n = recv( sockfd , buf, sizeof( buf ), 0 );/* 关闭套接字*/closesocket( sockfd );/* 终止客户程序*/exit(0);,4服务器实例代码/*-* 程序:server.c* 目的: 分配一个套接字,然后反复执行如下几步:* (1) 等待客户的下一个连接* (2) 发送一个短消息给客户* (3) 关闭与客户的连接* (4) 转向(1)步* 命令行语法: server port * port 服务器端监听套接字使用的协议端口号* 注意: 端口号可选。如果未指定端口号,服务器使用PROTOPORT中指定的缺省* 端口号*-*/,#include #include #include #include #include #include #define PROTOPORT 5188 /* 监听套接字的缺省协议端口号 */#define QLEN 6 /* 监听套接字的请求队列大小 */int visits = 0; /* 对于客户连接的计数*/,main(argc,argc)int argc;char* argv;struct hostent *ptrh; /* 指向主机列表中一个条目的指针 */struct sockaddr_in servaddr; /* 存放服务器网络地址的结构 */struct sockaddr_in clientaddr; /* 存放客户网络地址的结构 */int listenfd; /* 监听套接字描述符 */int clientfd; /* 响应套接字描述符 */int port; /* 协议端口号 */int alen; /* 地址长度 */ char buf1000; /* 供服务器发送字符串所用的缓冲区 */,memset( (char*) /* 否则,使用缺省端口号 */,if (port 0) /* 测试端口号是否合法 */servaddr.sin_port=htons( (u_short)port );else /* 打印错误信息并退出 */fprintf( stderr, ”bad portnumber %sn”, argv1 );exit(1);/* 创建一个用于监听的流式套接字 */listenfd = SOCKET(AF_INET,SOCK_STREAM,0);if (listenfd 0) fprintf( stderr, “socket creation failedn” );exit(1);,/* 将本地地址绑定到监听套接字*/if ( bind( listenfd, (struct sockaddr *),/* 服务器主循环接受和处理来自客户端的连接请求 */while(1) alen = sizeof(clientaddr); /* 接受客户端连接请求,并生成响应套接字 */if(clientfd = accept( listenfd, (struct sockaddr *) /* 关闭响应套接字 */,关于阻塞的问题,图2.7 服务器进程因调用ACCEPT()而被阻塞,2.3.4 进程的阻塞问题和对策,1什么是阻塞 阻塞是指一个进程执行了一个函数或者系统调用,该函数由于某种原因不能立即完成,因而不能返回调用它的进程,导致进程受控于这个函数而处于等待的状态,进程的这种状态称为阻塞。,图2.8 RECV()函数的两种执行方式,2能引起阻塞的套接字调用 在Berkeley套接字网络编程接口的模型中,套接字的默认行为是阻塞的,具体地说,在一定情况下,有多个操作套接字的系统调用会引起进程阻塞。(1)ACCEPT()(2)READ()、RECV()和READFORM()(3)WRITE()、SEND()和SENDTO()(4)CONNECT()(5)SELECT()(6)CLOSESOCKET(),3阻塞工作模式带来的问题 采用阻塞工作模式的单进程服务器是不能很好地同时为多个客户服务的。图2.9是一个例子。,图2.9 采用阻塞工作模式的服务器不能很好地为多个客户服务,4一种解决方案,利用UNIX操作系统的FORK()系统调用,编制多进程并发执行的服务器程序。可以创建子进程。对于每一个客户端,用一个专门的进程为它服务,通过进程的并发执行,来实现对多个客户的并发服务。基本的编程框架是:,父进程代码If (pid = FORK() = 0) .子进程代码. else if (pid0) 报错信息父进程代码,举例:#include #include #include #include void main(int argc, char* argv)int listenfd,clientfd,pid;struct sockaddr_in ssockaddr, csockaddr;char buffer1024;int addrlen,n;,/* 创建监听套接字 */listenfd = socket(AF_INET,SOCK_STREAM,0);if (listenfd 0) fprintf(stderr, socket error!n);exit(1);,/* 为监听套接字绑定网络地址 */memset(,/* 启动套接字的监听 */listen(listenfd,5);addrlen = sizeof(sockaddr);/* 服务器进入循环,接受并处理来自不同客户端的连接请求 */while (1) clientfd = accept(listenfd,(sockaddr*)(/* accept调用返回时,表明有客户端请求连接,创建子进程处理连接*/If (pid = FORK() = 0) ,/* 显示客户端的网络地址 */printf(Client Addr: %s%dn,inet_ntoa(csockaddr.sin_addr),ntohs(csockaddr.sin_port);/* 读取客户端发送来的数据,在将它们返回到客户端 */while (n = read(clientfd,buffer,1024) 0) buffern = 0;printf(Client Send: %s,buffer);write( clientfd, buffer, n);if (n 0) fprintf( stderr, read error!n);exit(3);,/* 通信完毕,关闭与这个客户连接的套接字 */printf(clent %s closed!n, inet_ntoa(csockaddr.sin_addr);close(clientfd);exit(1); else if (pid 0) printf(fork failed!n);close(clientfd);close(listenfd); /* 关闭监听套接字 */,2.4 无连接的套接字编程2.4.1 无连接的套接字编程的两种模式 使用数据报套接字开发网络应用程序,既可以采用客户/服务器模式,也可以采用对等模式。,图2.10 对等模式的数据报套接字的编程模型,1对等模式,2客户/服务器模式,图2.11 C/S模式的数据报套接字的编程模型,2.4.2 两个专用的系统调用1发送数据报SENDTO()int SENDTO( int sockfd, const void* msg, int len, unsigned int flags, struct sockaddr* to, int tolen);2接收数据报 RECVFROM()int RECVFROM( int sockfd, void* buf, int len, unsigned int flags, struct sockaddr* from, int* fromlen ),2.4.3 数据报套接字的对等模式编程实例聊天程序#include #include #include #include #include #include /* 中断处理过程 */void int_proc( int signo) ,void main(int argc, char* argv) struct sockaddr_in daddr, saddr, cmpaddr;int sockfd;int timer = 3;char buffer1024;int addrlen, n;/* 判断用户输入的命令行是否正确,如果有错,提示用法 */if (argc != 5) printf(用法:%s 目的IP 目的端口 源IP 源端口n, argv0);exit(0);,/* 设定中断处理函数,并设置时间限制 */signal( SIGALRM, int_proc);alarm(timer);/* 建立数据报套接字 */sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd 0) fprintf(stderr, socket error!n);exit(1);,/* 为结构变量daddr的各个字段赋值 */addrlen = sizeof(struct sockaddr_in);memset(,/* 为结构变量saddr的各个字段赋值 */addrlen = sizeof(struct sockaddr_in);memset(,/* 绑定地址 */if (bind(sockfd, ,while (1) /* 接收信息并显示 */n = recvfrom( sockfd, buffer, 1024, 0, , else /* 比较数据报来源地址与保存的目标地址是否一致 */* 不同则返回非0,结束此循环 */if (memcmp(cmpaddr, daddr,addrlen) continue;buffern = 0;printf( Received: %s, buffer);,/* 从标准输入获得字符串,并发送给目标地址 */if (fgets(buffer, 1024, stdin) = NULL ) exit(0);if ( sendto( sockfd, buffer, strlen(buffer), 0, ,2.5原始套接字,利用“原始套接字”(Raw Socket),可以访问基层的网络协议,如IP(网际协议)、ICMP(Internet控制消息协议)、IGMP(Internet组管理协议)等。很多网络实用工具,如Tracerout、Ping、网络嗅探器(sniffer)程序等,就是利用原始套接字实现的。,2.5.1 原始套接字的创建,格式一: Int sockRaw = socket(AF_INET,SOCK_RAW, protocol)格式二:SOCKET sockRaw = WSASocket (AF_INET, SOCK_RAW, protocol, NULL, 0, 0);,2.5.2 原始套接字的使用,1根据需要设置套接字的选项 2调用connect和bind函数来绑定对方和本地地址 3发送数据包4接收数据包,2.6 Linux系统的网络编程接口,在UNIX系统中,首先带有网络功能的版本是4.3BSD。Linux的网络功能就是以此为模型发展起来的,它支持BSD套接口和全部的TCP/IP功能。套接口类型 流式 、数据报 、原始,2.6.1 数据结构,Struct sockaddr Unsigned short sa_family;/ 地址家族 Char sa_data14;/14字节的协议地址 ,struct sockaddr_in short int sin_family;/ Address family unsigned short int sin_port;/ Port number struct in_addr sin_addr;/ Internet address unsigned char sin_zero8;/Same size as struct sockaddr ;,2.6.2 主要系统调用,1创建套接字 socket()2绑定套接字bind() 3连接connect()4启动监听listen()5accept()6发送send() 和接收recv()7sendto() 和recvfrom(),8关闭套接字close() 和shutdown()9getpeername()10gethostname()11使用IP地址,

    注意事项

    本文(网络编程实用教程第二版课件.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开