收藏 分销(赏)

计算机网络的迅速发展.doc

上传人:w****g 文档编号:2279227 上传时间:2024-05-24 格式:DOC 页数:49 大小:336.54KB 下载积分:12 金币
下载 相关 举报
计算机网络的迅速发展.doc_第1页
第1页 / 共49页
计算机网络的迅速发展.doc_第2页
第2页 / 共49页


点击查看更多>>
资源描述
个人收集整理 勿做商业用途 摘要 计算机网络的迅速发展,对人类社会诸多领域产生了巨大的影响。在诸多支持网络的操作系统中,LINUX以其优秀的性能越来越引起人们的关注。本次毕业设计的任务为分析LINUX网络编程环境,并实现一个LINUX局域网的电子邮件系统。 本毕业设计论文分为两大部分。第一部分对LINUX以及LINUX网络编程环境作了一个介绍。详细分析了编程中将用到的BSD套接字函数族的使用.第二部分记录了本人与合作者唐志军开发的邮件系统的实现过程,从总体分析、模块划分到详细设计,并在后面附了本人实现的C语言源代码。 关键字: Linux, 网络编程,套接字,服务器,客户端,电子邮件系统 Abstract The rapid development of the computer networks has been making a great influence in many fields of human society。 Among a great many networks operating systems, Linux is obtaining more and more attention from people by its excellent behavior。In this graduate design, our task is to develop a e-mail system based on a lan with Linux as its operating system。 This article includes two parts。 In part one, we will make an introduction to Linux operating system and the network programming environment in Linux. In particular, the BSD socket functions are analyzed in great detail, for they will be used in later programming work. In part two, we present the implementation of our mail system, from whole designing to detail designing, and the C program source files written by me is attached to the end of this article。 Keywords: Linux, network programming , socket, server, client, e—mail system 目录 第一部分 环境分析 第一章 LINUX的发展历史及趋势…………………………………….3 第二章 LINUX网络编程环境分析 第一节 套接字简介…………………………………………4 第二节 socket编程的基本流程……………………………。4 第二节 BSD套接字函数介绍………………………………5 第二部分 邮件系统实现 第三章 邮件系统介绍 第一节 概述…………………………………………………13 第二节 模块划分……………………………………………14 第三节 服务器程序和客户端程序的详细设计与分析……16 设计体会与致谢………………………………………………………………。…29 参考文献…………………………………………………………………………。30 附录 服务器程序和客户端程序的源代码…………………………………………………。.31 第一章 LINUX的发展历史及趋势 在迅猛发展的国际互联网上,有这样一群人,他们是一支由编程高手、业余计算机玩家和黑客们组成的奇怪队伍,完全独立的开发出在功能上毫不逊色于微软的全新的免费UNIX操作系统——Linux,成为网络上一支不可轻视的力量,短短几年时间就成了微软的一个强劲对手。 LINUX是什么?按照LINUX开发者的说法,LINUX是一个遵循POSIX标准的免费操作系统。要追述LINUX的发展历史,要先从UNIX谈起。 1969~1970年间,美国电报电话公司(AT&T)Bell实验室Dennis Ritchie和Ken Thompson首先PDP-7机器上实现了UNIX系统。之后又不断推出新的版本。由于UNIX的一下特征:开放性、多用户多任务环境、功能强大、效率高、提供丰富的网络功能等,UNIX操作系统取得了巨大的成功,广泛应用于金融、军事等社会各领域。 1987年,为了教学目的,计算机科学家Andrew S Tanenbaum开发了一套功能简单易懂的类UNIX操作系统Minix。1991年,一位来自芬兰赫尔辛基大学的年轻人Linus Benedict Torvalds在实习Minix时发现它功能还很不完善,于是决心自己写一个保护模式下的操作系统,这就是Linux的原型。之后随着不断的完善,和GNU软件的支持,LINUX已经是一个功能强大的类UNIX操作系统了.它继承了UNIX的所有优点,而且具有源代码开放的最大特色,过去十年中它取得了惊人的成就,而且将更快的发展下去。 Linux目前已经进入了许多主流公司的事业,电信、金融、政府、军事等领域也广泛采用它.目前LINUX的发展趋势为分布式和嵌入式。当今计算机科学的比较前沿的课题集群系统超级服务器就多采用LINUX操作系统。可见LINUX在网络和分布式系统的应用将是很有前景的。这次毕业设计就是探讨LINUX的网络编程开发环境,并尝试实现一个基于Linux局域网的电子邮件系统,为将来在这方面的发展打下一个基础. 第二章 LINUX网络编程环境分析 第一节 套接字简介 网络程序设计全靠套接字(SOCKET)接收和发送信息.什么是套接字?套接字的英文原意是“孔”或“插座”,作为BSD UNIX的进程通信机制,取后一种意义.套接字实质上提供了进程通信的端点.进程通信之前,双方首先必须各自创建一个端点,否则没有办法建立联系并相互通信的。正如打电话之前,双方必须拥有各自的电话机一样。在电话系统中,一般用户只能感受到本地电话机和对方电话号码的存在,建立通话的过程、话音传输过程等技术细节对他是透明的额。这与套接字机制非常相似.套接字利用网络通信设施进行通信,但他对通信设施的细节毫不关心。 在UNIX系统中,任何对I/O的操作都是通过读或写一个文件描述符来实现的.一个文件描述符只是一个简单的整形数值,它代表一个被打开的文件(这里的文件指广义的UNIX文件)。套接字在系统中以文件描述符的形式存在.一个套接字可以这样来解释:它是通过标准的UNIX文件描述符和其他程序通信的一个方法。一个套接字对应一个文件描述符,由操作系统分配.服务器进程或客户进程可以象操作文件一样操作它。进行诸如创建、读、写、删除等操作,从而实现网络通信。事实上,利用套接字通信的基本过程就是先调用socket()函数,它返回一个套接字描述符,再对这个描述符进行一些操作如:系统函数send(),recv(),read(),write()等等。 套接字是面向客户-服务器模型设计,针对客户和服务器提供不同的套接字操作。客户随机申请一个套接字号,服务器拥有全局公认的套接字号,任何客户可以向它发出连接请求和信息请求。 套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字。流式套接字可以提供可靠的、面向连接的通信流。通过流式套接字接收的数据顺序和发送的数据顺序是一致的。数据报套接字定义了一种无连接的服务,数据通过相互独立报文进行传输,是无序的,并且不保证可靠、无差错。原始套接字允许对底层协议如IP和ICMP直接访问,主要用于新的网络协议的实现的测试等。 第二节 socket编程的基本流程 Socket编程的的基本模式是Client/Server。Server端首先调用socket创建一个一定类型的socket。然后通过bind函数将这个socket绑定到一个Client知道的端口上,接着server调用accept函数设置倾听队列的长度,为接收来自Client端的请求做准备,而后Server调用Accept,开始在所绑定的端口倾听来自Client端的连接请求.如果Socket被设置成阻塞方式,Accept调用将被阻塞,进程被挂起,直到Server收到来自Client的请求后,Accept才返回。 Client端通过socket调用创建一个一定类型socket(应当Server的socket类型相同)。然后调用connect函数向Server所在主机发出连接请求,连接时,需要指定Server所在主机的IP地址和正在倾听的端口号。Server收到Client的连接请求后,向Client发回应.Client端收到回应后,又向Server发回应信号,并从connect函数返回,返回值是一个打开的socket描述符.稍后,Server收到回应后从accept函数返回,返回值也是一个打开的socket描述符。以上过程体现了TCP协议三次握手建立连接的思想。 然后双方可以通过操作各自的描述符来进行传输数据。一方使用write将要发送的数据写到TCP的缓冲区,由TCP层负责写向网络,另一端通过read将数据从TCP缓冲区中读出。read和write系统调用和对文件的读写相似. 当数据传输完毕,双方都调用close()关闭各自套接字,终止通信。 第三节 BSD套接字基本函数介绍 2.3。1 函数socket() 函数socket()用于创建一个socket描述符,其定义如下: #include〈sys/types。h〉 #include〈sys/socket。h> int socket(int domain,int type,int protocol); 参数domain用于指定要创建的套接字使用的协议簇,可设置为AF_INET(TCP/IP协议簇),AF_UNIX(UNIX域协议簇)或AF_ISO(ISO协议簇).参数type指定套接字的类型,可以为SOCK_STREAM(流套接字),SOCK_DGRAM(数据报套接字),SOCK_RAW(原始套接字)。参数protocol一般可设置成0,表示通过指定的协议簇和需要的套接字的类型,就是系统可以确定程序需要使用的具体协议,比如流套接字和数据报套接字分别对应的TCP和UDP协议。 以下代码将创建一个TCP的套接字描述符: int sock_fd=socket(AF_INET,SOCK_STREAM,0); if (sock_fd<0) { perror(”socket creating error"); exit(1); } 如果socket调用失败,将返回-1,并将设置errno,以标识错误原因。 2。3.2 函数connect() * 函数定义 函数connect()用于向服务器发出连接请求.其定义如下: #include<sys/types.h〉 #include<sys/socket。h〉 int connect(int sockfd,struct sockaddr* servaddr,int addren); 参数sockfd是在socket()函数中返回的套接字描述符.参数servaddr用于指定服务器的地址和服务器端使用的传输端口号,以及地址类型。参数addrlen指定这个套接字地址的长度。 * 套接字地址 结构struct sockaddr定义了一种通用的套接字地址,其定义如下: struct sockaddr { unsigned short sa_family; /*地址类型*/ char sa_data[14]; /*14字节的协议地址*/ }; 其中,sa_family为套接字的协议簇地址类型,比如TCP/IP协议簇的地址类型为AF_INET;参数sa_data中存储具体的地址内容。 每一种具体的协议簇都将定义自己的协议地址类型,TCP/IP协议簇定义了sockaddr_in 描述自身的协议地址: struct in_addr{ _u32 s_addr; /*unsigned long 32比特的IP地址 */ }; struct sockaddr_in { short int sin_family; /*地址类型*/ unsigned short int sin_port; /*端口号*/ struct in_addr sin_addr; /*Internet地址*/ unsigned char _pad[_SOCK_SIZE—sizeof(short int)-sizeof(unsigned short int)—sizeof(struct in_addr)]; /*填充比特*/ }; 在编写TCP和UDP的代码时,通常直接使用struct sockaddr_in 结构来赋值,然后将它强制转化成套接字的地址结构。 *网络字序及其相关函数族 由于不同计算机内部对变量的字节存放的顺序可能不同.有的系统设计时,将变量的高端放在高字节,有的恰恰相反。所以,如果在将数据发到网络前不进行调整的话,a=0x0001将有可能被理解为a=0x0100。为了消除这种差异,协议规定在Internet上使用的网络字节顺序采用顺序存放。在编写程序时,无论本地字序是否与网络字序相同,都应调用相应的函数进行转化。 Linux系统提供了4个库函数来进行字节顺序的转化: #include<netinet/in。h〉 unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsinged long int netlong); unsigned short int ntohs(unsigned short int netshort); htonl代表host to network long对unsinged long int 型的变量转化成网络中使用的字节顺序。htons表示host to network short,对unsigned short int 类型的变量进行转化。ntohs和ntohl的功能和htons、htonl相反. *connect()函数使用示例: struct sockaddr_in serv_addr; int ret,sock_fd; bzero(&serv_addr,sizeof(struct sockaddr_in)); serv_addr。sin_family=AF_INET; serv_addr.sin_port=htons(SERVER_PORT); ret=inet_aton("127.0.0。1”,&serv_addr。sin_addr); if (ret<0) { perror("convert IP address error"); exit(1); } ret=connect(sock_fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in)); if (ret<0) { perror(”connect to server error"); exit(1); } 和socket()函数相似,如果连接失败,将返回-1,并使用errno还表示错误的原因。 2。3。3 函数band() bind()将一个未名名的套接字一个名字,在函数socket()中,核心只是创建了一个套接字结构,但是这个套接字将工作在哪个传输层端口上,核心并没有指定。如果进程需要使用某一个固定端口,则需要程序来提供端口信息。在server进程中,由于进程通常使用的是一个熟知端口,所以需要调用bind()向系统登记一个固定端口. bind()函数定义如下: #include<sys/types.h〉 #include〈sys/socket。h〉 int bind(int sockfd,struct sockaddr *my_addr,int addrlen); sockfd是由socket()函数返回的套接字描述符。my_addr是一个指向struct sockaddr的指针,包含有关的地址信息:名称、端口和IP地址。addrlen为地址长度,可设置为sizeof(struct sockaddr). 下面几行代码显示了bind()的使用: struct sockaddr_in serv_addr; bzero(&serv_addr,sizeof(struct sockaddr_in); serv_addr。sin_family=AF_INET; serv_addr.sin_port=htons(SERVER_PORT); serv_addr。sin_addr.s_addr=htonl(INADDR_ANY); ret=(bind(sock_fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); if (ret〈0) { perror("bind to SERVER_PORT error"); exit(1); } 这里的INADDR_ANY的含义是任何网络设备接口。对于一台只有一个IP地址的主机,它就对应于它的IP地址。 2.3.4 函数listen() 函数listen()把套接字转化为一个被动倾听套接字,并在套接字指定的端口上开始倾听。函数形式如下: #include〈sys/socket.h〉 int listen(int sockfd,int backlog); 参数sockfd是在bind之后已经命名的套接字,backlog指定连接请求队列的最大长度.如果函数成功返回0,否则返回—1。 由函数socket创建的是主动的套接字,也就是说是可以通过调用connect主动请求连接到某个服务器进程的套接字.但是作为服务器进程,通常应当在某个熟知端口上等待,所以需要调用listen向系统申明自己希望在哪个端口倾听,哪个端口上的TCP连接状态将被设置成LISTEN。 2。3。5 函数accept() 函数accept()从完全建立连接的队列中接受一个连接。函数的形式如下: #include〈sys/socket.h> int accept(int sockfd,struct sockaddr *addr,int *addrlen); 参数sockfd是被设置为倾听的被动套接字描述符,参数addr是指向套接字地址结构的指针,它将保持连接对端的地址信息.参数addrlen是对端套接字的长度。如果程序对客户进程的地址不感兴趣,则可以将addr和addrlen设置为NULL。 当accept()成功返回时,将返回一个新的套接字描述符。这个套接字不同于服务进程用于倾听的被动套接字描述符(listen socket descriptor),被动套接字只能用于接收客户进程的连接请求.而这个新的套接字描述符就象打开一个新文件返回文件的描述符一样,进程可以使用这个新的套接字描述符向客户端写数据或者从对端接受数据.这个新套接字描述符称为连接套接字描述符(connected socket descriptor)。 2.3。6 函数read()和write() read()和write()用于数据的接收和发送.其形式为: int read(int fd, char *buf, int len); int write(int fd, char *buf, int len); 参数是由connect返回(客户进程)或者accept(服务器进程)的连接套接字描述符。read中的buf是应用的发送缓冲区,而write中的buf是应用的接收缓冲区。参数len是用于指定希望发送或接收的数据的字节数。 如果read函数成功,将返回实际读取的数据的字节数.如果read返回0,则表示对端已经关闭了写管道,相当于收到文件结束符EOF。如果read出错,则返回-1,并设置errno。 write和read相似,将返回实际写出的数据的字节数。 2.3。7 函数recv()和send() 函数recv()的功能和read()相似,它在read()的功能的基础上,增加了4个参数用来对套接字的读操作进行控制,函数形式如下: #include〈sys/types.h〉 #include<sys/socket.h> int recv(int sockfd,void *buf,int len,int flags); 函数send()的功能和write()相似,它在write()的功能的基础上,增加了4个参数用来对套接字的写操作进行控制,函数形式如下: #include<sys/types。h〉 #include〈sys/socket.h〉 int send(int sockfd,void *buf,int len,int flags); 2.3。7 函数close() 函数close()用于关闭一个套接字描述符。套接字描述符和文件描述符的操作相似.其形式如下: #include<unistd。h> int close(int sockfd); 通常close在关闭一个TCP连接时,close将立即返回.进程将不能再使用套接字描述符来访问套接字,但是TCP可能并没有删除套接字结构,因为可能在发送数据缓冲区还有数据没有发送完.TCP将继续发送剩余的数据,并在最后的数据段附加FIN控制信息。 基本的套接字函数就是上述几个,用以上几个函数就能进行基本的服务器和客户端的通信了。下面给出一个对以上函数应用的简单的例子:实现由服务器向客户端发送一个字符串“HELLO WORLD!”。这是套接字网络编程最简单的应用,后面实现的邮件系统就是在此基础上做一些改动和功能上的添加。 服务器代码: #include〈stdlib.h> #include<errno.h〉 #include〈string。h〉 #include〈sys/types.h〉 #include〈netinet/in。h〉 #include〈sys/socket。h> #include〈sys/wait.h〉 #define MYPORT 4050 #define BACKLOG 10 main() { int sockfd,new_fd; struct sockaddr_in my_addr; struct sockaddr_in their_addr; int sin_size; if ((sockfd=socket(AF_INET,SOCK_STREAM,0))==—1){ perror("socket"); exit(1); } else { printf(”socket created successfully!\n"); } my_addr。sin_family=AF_INET; my_addr。sin_port=htons(MYPORT); my_addr.sin_addr.s_addr=INADDR_ANY; bzero(&(my_addr。sin_zero),8); if (bind(sockfd,(struct sockaddr*) &my_addr,sizeof(struct sockaddr))==-1) { perror("bindB”); exit(1); } else printf("address binded successfully!\n”); if (listen(sockfd,BACKLOG)==-1) { perror(”listen”); exit(1); } else printf("start listening the clients’ connect request.。。.。.\n"); while(1) { sin_size=sizeof(struct sockaddr_in); if ((new_fd=accept(sockfd,(struct sockaddr*)&their_addr,&sin_size))==-1) { perror(”accept”); continue; } printf(”server:got connection from %s\n",inet_ntoa(their_addr.sin_addr)); if (!fork()) if (send(new_fd,"Hello,World!\n”,14,0)==-1) { perror("send"); close(new_fd); exit(0); } close(new_fd); } while(waitpid(-1,NULL,WNOHANG)〉0); } 客户端程序: /*头文件同上*/ #define MAXDATASIZE 100 int main(int argc,char **argv) { int sockfd,numbytes,servport; struct sockaddr_in servaddr; char buf[MAXDATASIZE]; if (argc!=3) { fprintf(stderr,”usage:hellocli <server's ip address> 〈server’s port>"); exit(1); } sockfd=socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(struct sockaddr_in)); servaddr.sin_family=AF_INET; servaddr。sin_port=htons(atoi(argv[2])); inet_aton(argv[1],&servaddr.sin_addr); connect(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr)); if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==—1) { perror(”recv"); exit(1); } buf[numbytes]='\0’; printf(”Receive from server %s :\n %s”,argv[1],buf); printf("totally %d bytes received\n\n",numbytes); close(sockfd); printf(”。。。.。.local socket closed\n"); return 0; } 第二部分 第三章 邮件系统的实现 第一节 概述(问题定义、需求分析和可行性分析) 前几章对LINUX系统提供的网络编程接口进行了分析,为第二部分的内容——实现一个C/S模型的局域网内的电子邮件系统——打下了基础。接下来的章节将给出该邮件系统的概述、总体设计、详细设计和本人编写的服务器程序和客户端程序的源代码。 为方便起见,将要实现的邮件系统命名为DTMS。由于是为了实习目的模拟现实的邮件系统,该邮件系统较现实中的邮件系统功能上有较大的简化.具备的是邮件系统必备的一些基本功能.如:申请新邮箱、注销邮箱、发邮件、阅读邮件、删除邮件、保存邮件。 从服务器和客户端的角度,它们分别需实现以下功能: 服务器: 1、保存用户信息(帐号密码对) 2、验证登录用户密码 3、邮件接受转发功能(接受发信用户发来的邮件,将邮件发给收信用户) 4、邮件管理功能(保存,打开,删除等) 客户端: 1、选择需要的服务 2、读邮件,删邮件,编辑邮件,发送邮件 另外,在以下四种场合,服务器和客户端需共同完成通信的功能: 1、客户端向服务器发送服务请求、密码等信息 2、服务器向客户端发送响应信息(服务完成、密码验证信息等) 3、客户端向服务器传送邮件 4、服务器向客户端传送邮件 服务器和客户端分别需实现的功能可以采用LINUX 系统提供的文件操作系统调用实现。服务器和客户端共同完成的通信功能可使用LINUX系统提供的BSD SOCKET网络编程接口实现。总之,对上述功能,该系统的实现在目前的知识基础上是可行的。 第二节 模块划分 整个系统由服务器程序和客户端程序两大部分组成.服务器程序由两大模块组成:通信模块和服务器文件处理模块;客户端程序也由两大模块组成:通信模块和界面提供模块。基本结构如下: 服务器主程序调用以下两大模块: 1、服务器文件处理模块 ⑴信件管理子模块 (打开邮件列表,打开邮件,删除邮件) ⑵用户信息管理子模块 (保存帐号密码对,验证密码) 2、 服务器通信模块 (服务器向客户传邮件,服务器向客户传服务响应信息) 客户端主程序调用以下两大模块 1、客户端界面提供模块 2、客户端通信模块 (客户向服务器传邮件,客户向服务器传服务请求信息) 我们实现的邮件系统的运行大致过程为:服务器和客户机分别进入主程序,调用各自通信模块建立连接.同时,客户端调用界面提供模块提供菜单式的操作界面,等待用户根据菜单提示选择需要的服务,通信模块将用户选择的服务用字符串的形式发送给服务器,服务器根据收到的字符串判断用户需要的哪种服务,调用文件处理模块中的相应服务子程序(函数)来提供特定服务。并同时在需要时调用通信模块向客户端发回应信号或传送文件。 下面对各模块的功能和实现方案详细解释说明如下: 1、服务器文件处理模块: 包括两个子模块,信件管理模块和用户信息管理子模块。这两个子模块功能上是独立的,各自包含一些服务子程序.实现的方法是一样的,同为利用LINUX提供的文件操作系统调用。为满足邮件系统提供的基本功能,文件处理模块需具备以下文件: (1)用户信息文件一个:保存各用户的帐号密码信息,以记录形式保存。 (2)邮件列表文件若干:为各用户保存各自的邮件列表,以记录形式保存,记录包括寄信者,邮件编号,发信时间,主题等项. 每个用户拥有一个邮件列表文件。 (3)邮件文件若干:保存用户的邮件内容。 2、信件管理子模块:该模块包含打开邮件、保存邮件、删除邮件功能,分别由一个函数实现。 (1)打开邮件列表:在用户登录成功时,即用户输入用户名密码得到正确验证时调用此功能。用一个函数读取该用户的邮件信息文件,产生一个邮件列表的临时文件,并通过通信模块将该临时文件的内容传至客户机。 (2)打开邮件:在收到客户“读邮件”命令时调用此功能。根据用户名以及用户传过来的邮件号码,打开相应邮件,通过通信模块将邮件内容传给客户机。 (3)删除邮件:在收到客户“删除邮件”命令时调用此功能.根据用户名及用户传过来的待删邮件的号码利用系统调用将相应邮件删除。并修改保存该用户邮件列表的文件。 3、用户信息管理子模块:该模块包含保存、删除帐号密码对,验证密码三个功能。 (1)保存用户密码对:在新用户注册时,即用户选择“注册”命令,并将用户名和密码传到服务器时调用此功能,将新用户的信息--用户密码对添加到用户信息文件中. (2)验证密码:在用户登录,并发送帐号密码到服务器后调用此功能.实现原理为根据欲登录用户发过来的用户密码对查找服务器上的用户信息文件.若查找成功,发提示信息到客户端,并转入调用打开邮件列表的服务程序.若查找失败,发失败提示信息到客户端,等待用户重新输入帐号密码。 4、服务器端通信模块 服务器程序在启动时便调用SOCKET函数族,创建套接字,绑定端口,开始等待客户端的连接。当有用户进入邮箱,即建立连接。并根据用户的不同服务请求,利用建立好连接的套接字传送或接收数据。在以下四个场合需要调用服务器端的read/write或send/revc函数与客户端通信: (1)服务器向客户端发服务响应信息(字符串形式) (2)服务器向客户传送邮件(服务器打开邮件文件,传输文本,客户接收文本写入本地新文件) (3)客户端向服务器发服务请求(字符串形式) (4)客户端向服务器传送邮件(客户打开邮件文件,传输文本,服务器接收文本写入本地新文件) 5、客户端界面提供模块
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 考试专区 > 中考

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服