ImageVerifierCode 换一换
格式:DOCX , 页数:21 ,大小:141.87KB ,
资源ID:12198535      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/12198535.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(网络编程 发送what is time 返回时间.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

网络编程 发送what is time 返回时间.docx

1、网络编程 发送what is time 返回时间网络程序设计课程设计报告 目录第一章 实验目的和要求 11.1实验目的 11.2实验要求 11.3 实验内容 1第二章 实验内容 22.1对题目的分析 22.2守护进程的原理 3第三章 设计实现 43.1关键技术分析 43.1.1创建守护进程 43.1.2 I/O复用的select函数 63.1.3网络套接字函数 73.2关键程序代码分析 83.2.1创建守护进程 83.2.2套接字编程 93.2.3 I/O复用的select函数 103.2.4处理客户连接 10心得体会 11参考文献 12附录1程序界面截图 13附录2 源代码 14第一章 实验

2、目的和要求1.1实验目的(1)熟练掌握所学到的网络套接字函数;(2)掌握UDP和TCP编程关键函数;(3)掌握多进程或多线程编程;(4)掌握使用select实现I/O复用;(5)掌握守护进程的编写。1.2实验要求(1)认真阅读和掌握本实验的相关的知识点。(2)上机编写并运行程序。(3)保存和打印出程序的运行结果。1.3 实验内容本次课程设计题目如下:(1)实现一个并发、IO复用的守护进程时间服务器,要求当客户端向服务器发送“whats time?”字符串时,服务器回应当时的系统时间字符串。(2)实现一个类似于“飞鸽传书”的文件传输软件,要求其具有并发并发性、IO复用性。当用户使用软件时要求指明

3、“目的ip地址”和“要传输的文件的路径”。第二章 实验内容2.1对题目的分析我们选择实验的题目1即实现一个并发、IO复用的守护进程时间服务器,要求当客户端向服务器发送“whats time?”字符串时,服务器回应当时的系统时间字符串。现在要用守护进程实现一个时间服务器,呈现的功能是:服务器运行后自动成为守护进程,返回shell;客户端运行后收到服务器发来的当前时间。从而达到利用网络把时间资讯传递给用户的目的。要使服务器可以同时处理多个客户端的请求需要用到并发服务器,我们采用I/O多路复用。详细过程如图2-1服务器端工作流程图所示。图2-1服务端工作流程图2.2守护进程的原理 在Client/S

4、erver模式下,服务器监听(Listen)在一个特定的端口上等待客户连接。连接成功后服务器和客户端通过端口进行数据通信。守护进程的工作就是打开一个端口,并且等待(Listen)进入连接。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继续监听其他的服务请求。 独立运行的守护进程由init脚本负责管理,所有独立运行的守护进程的脚本在/etc/rc.d/init.d/目录下。系统服务都是独立运行的守护进程包括:syslogd和cron等。运行独立的守护进程工作方式称作:standalone。它Unix传统的C/S模式的访问模式。服务器监听(Listen)

5、在一个特点的端口上等待客户端的联机。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继续监听。以保持多个子服务器池等待下一个客户端请求。工作在standalone模式下的网络服务有route、gated。另外是大家最熟悉是Web服务器:Apache和邮件服务器Sendmail、域名服务器Bind。因为这些负载很大服务器上,预先创子服务器,可以通过客户的服务速度。在Linux系统中通过standalone工作模式启动的服务由/etc/rc.d/下面对应的运行级别当中的符号链接启动。第三章 设计实现3.1关键技术分析3.1.1创建守护进程 在linux操作

6、系统中在系统的引导的时候会开启很多服务,这些服务就叫做守护进程。守护进程是脱离于终端并且在后台运行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程常常在系统引导装入时启动,在系统关闭时终止。由于在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,

7、相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到整个系统关闭时才退出。如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。创建一个守护进程如下图2-2守护进程:图2-2 守护进程服务器流程图 创建守护进程,要先创建子进程,然后再退出父进程。 使用的是系统函数setsid在子进程中创建新会话,从而使进程完全独立出来,从而摆脱其他进程的控制。 改变当前目录为根目录,利用chdir(“/”)更改。 重设文件权限掩码,使新文件的权限位不受原文件模式创建掩码的权限位的影响,使用函数umask()。 close()关闭文件描述符。同

8、文件权限码一样,用fork函数新建的子进程会从父进程那里继承一些已 经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,但它 们一样消耗系统资源,而且可能导致所在的文件系统无法卸下,所以应该 被关闭。3.1.2 I/O复用的select函数我们需要服务器具有这样的能力:如果一个或多个I/O条件满足(如输入已准备好被读,或描述字可以承接更多的输出)时,就被通知到。这个能力被称为I/O复用,详细过程如图2-3 I/O复用的过程。图2-3 I/O复用的过程如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般要用到I/O复用。select的功能可以用一句话来描述:实现基于I/O多

9、路复用的异步并发编程。当server要对外提供大量的client请求服务时,假如使用阻塞方式,在单线程中,由于accept和recev都是阻塞式的,那么当一个client被服务器accept后,它可能在send发送消息时阻塞,因此服务器就会阻塞在recev调用。即时此时有其他的client进行connect,也无法进行响应。而如果使用select,在服务器端先注册由socket创建的文件描述符,然后进入select调用。只有当由socket创建的文件描述符的状态发生改变时,才执行accept操作,并把得到的client的文件描述符进行注册,再次进入select调用。当select检查到有文件描

10、述符的状态改变时,如果是server的socket创建的文件描述符,则执行accept操作,否则执行recev操作。当请求的client数目比较多时,select明显能够提高并发性。3.1.3网络套接字函数面向连接的客户机/服务器程序工作模式,服务器进程首先用socket()建立流套接字,在用bind()套接字与本地地址绑定,在用listen()侦听,即准备好接受连接,在用accept()接收连接,然后等待客户进程连接请求的到来,在用recv()接收数据,send()发送数据,最后用close()关闭套接字;客户端进程,首先用socket()建立套接字,在用connect()将套接字与远程主机

11、连接,在用send()发送数据,recv()接收数据,最后用close()关闭套接字。如下图3-3 面向连接的客户/服务器程序工作模式描绘了网络套接字编程的过程。图3-3 面向连接的客户/服务器程序工作模式3.2关键程序代码分析3.2.1创建守护进程 第一次调用fork的目的是保证调用setsid的调用进程不是进程组长。(而setsid函数是实现与控制终端脱离的唯一方法)。 setsid函数使进程成为新会话的会话头和进程组长,并与控制终端断开连接。 第二次调用fork的目的是:即使守护进程将来打开一个终端设备,也不会自动获得控制终端。这样可以保证这次生成的进程不再是一个会话头。 忽略SIGHU

12、P信号的原因是,当第一次生成的子进程(会话头)终止时,该会话中的所有进程(第二次生成的子进程)都会收到该信号。3.2.2套接字编程 bind()函数就是绑定函数,其作用是调用socket()函数产生的套接字分配一个本地协议地址,建立地址与套接字的对应关系。进程如果绑定了一个特定的本地IP地址到它的套接字上,对于TCP客户端,这就是此套接字上发送的IP数据包分配了源IP地址;对于TCP服务器端,这就限制了该套接字只接受目的地址为IP的客户连接。 socket()创建TCP套接字,作为TCP通信的传输端点,函数中的family参数指明协议族,type参数指明产生套接字的类型,protocol参数是

13、协议标志,一般在调用socket()函数时将其置为0。 listen()函数,在调用之后服务器的状态从CLOSED转换到了LISTEN状态。参数sokfd是要设置的描述符;backlog参数规定了请求队列中的最大连接数,对队列中等待服务请求的数目进行了限制。如果一个服务请求到来时,输入队列已满,该套接字将拒绝连接请求。 accept()函数使服务器接受客户端的连接请求,它将完成队列中的对头条目返回给进程,并产生一个新的套接字描述符,这个新生成的描述符称为“已连接套接字”当已完成对列为空时,进程睡眠,直到有已完成的连接到达时。 TCP客户端使用connect()函数来配置套接字,建立一个与TCP

14、服务器的连接,Connect()函数用于激发TCP的三次握手过程,建立与远程服务的连接,对于TCP连接的状态,conect()导致客户端从CLOSED状态转到了SYN_SENT状态。若建立成功,也就是connect()调用成功,状态会再变到ESTABLISHED状态;若函数connect()调用失败,则套接字不能再使用,必须关闭。如果想重新调用socket()函数,生成新的套接字。 bzero()中server 要置零的数据的起始地址。从&servaddr指针所指的地址位置开始, 将sizeof(sevaddr)字节置为0,bzero无返回值,并且使用string.h头文件sizeof 的结果

15、等于对象或者类型所占的内存字节数。 sockaddr_in为IPv4套接字地址结构通常也称为“网际套接字地址结构”,名字为 sockaddr_in。 htons将一个无符号短整型(16位)的主机数值转换为网络字节顺序。 SOCK_STREAM提供面向连接的稳定数据传输,即TCP协议。OCK_STREAM应用在C语言socket编程中,在进行网络连接前,需要用socket函数向系统申请一个通信端口。3.2.3 I/O复用的select函数 select()它允许进程指示内核等多个事件中的任意一个发生,并仅在一个或多个事件发生或经过指定时间时唤醒进程。 listenfd参数是由socket()函数

16、产生的套接字描述符,在调用accept()函数前,已经调用listen()函数将此套接字变成了监听套接字。 cliaddr和len用来返回对方的套接字地址结构和对应的结构长度。3.2.4处理客户连接 connfd是套接字描述符,对于服务器是accept()函数返回的已连接套接字描述符,对客户端是调用socket()函数返回的套接字描述符。 buff是指向发送信息的数据缓冲区。 strlen(buff)指明传送数据的长度。 write()发送成功后返回发送的字节数,失败返回-1。心得体会在本次网络程序设计课程设计中,我们小组选中的题目是“服务器端客户端通信”,即用守护进程创建一个时间服务器,实现

17、客户端与服务器端的连接。当然,这个题目最重要的地方并不在于服务器端与客户端实现了通信,最重要的是以守护进程的方式来实现并且要运用I/O复用。守护进程,能够突破传统的进程创建与退出方式,不再是随着控制终端的打开和关闭而创建和退出,而是自己成为一个独立的部分,随着整个系统实行运转,不因用户或终端而受到影响,这是以守护进程创建的服务器的最大的优点,而I/O复用要解决TCP服务器既要处理监听端口又要处理以监听端口的问题。在刚开始确定了这个题目的时候,我们先调试了书上的代码,发现书上给出的程序宏观上符合本次课程设计的概况要求,我们把代码分成若干块,以书中的程序为基础删除和添加功能,在服务器端的程序中,在

18、定义完一系列的头文件后,先用一个函数创建守护进程,其次,编写带有select()函数的I/O复用的并发TCP服务器实现接收客户端消息;在客户端程序中,首先,实现输入字符串并且比较该字符串是否同定义的“whats time”相同,其次,实现同数据端的连接收发数据。这样,整个代码看起来功能层次分明,也便于学习。因此,要完成一项任务,我们要从自己的实际出发,既不能局限于书本上的知识,我们一定要站在自身的角度上,刻苦学习,悉心钻研,这样才能圆满的完成任务。参考文献1甘刚著.Linux/UNIX网络编程.北京:中国水利水电出版社,2008附录1程序界面截图 我们在Linux环境下使用C语言完成了“客户端

19、和服务器端的通信”实现了一个并发 I/O复用的守护进程时间服务器。实现结果如下图:图附录1-1 程序运行效果截图附录2 源代码服务器:#include #include #include #include #include #include #include #include #include #include #define IPADDRESS 127.0.0.1#define PORT 1234#define BUFFMAX 1024#define BACKLOG 5#include#include#include#define MAXFD 64/*定义守护进程函数*/void daemo

20、n_init(const char *pname,int facility) int i; pid_t pid; /*为避免挂起控制终端将Daemon放入后台执行*/ if (pid=fork()!=0) exit(0); /是父进程,结束父进程,子进程继续 /*脱离控制终端,登录会话和进程组 */ setsid(); /使进程成为会话组长 /由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 /*处理SIGCHLD信号*/ signal(SIGHUP,SIG_IGN); /如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。 /如果父进程等待子进程结束,将

21、增加父进程的负担,影响服务器进程的并发性能。 /*禁止进程重新打开控制终端 */ if(pid=fork()!=0) exit(0); /*第一个子进程终止*/ /*将工作目录改变到根目录*/ chdir(/); /*清除文件模式创建掩码*/ umask(0); /*关闭所有打开的文件描述字*/ for(i=0;iMAXFD;i+) close(i); /*用syslogd处理错误*/ openlog(pname,LOG_PID,facility); /end daemon_init/声明I/O多路复用select函数static void select_(int listenfd);/声明处

22、理客户端函数static void deal_date(int *connfds,int num,fd_set *prset,fd_set *pallset);/主函数int main(int argc,char *argv) /struct sockaddr_in cliaddr;/IPv4套接字地址结构通常也称为“网际套接字地址结构”,名字为sockaddr_in。 /socklen_t cliaddrlen;/unsigned int /*调用守护进程函数*/ daemon_init(argv0,0); /*生成TCP套接字*/ int sockfd; if(sockfd = socke

23、t(AF_INET,SOCK_STREAM,0)=-1);/IPv4协议,字节流套接口 /*对服务器的结构初始化并赋值*/ struct sockaddr_in server; bzero(&server,sizeof(server); server.sin_family = AF_INET; /inet_pton(AF_INET,IPADDRESS,&server.sin_addr); server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(PORT); /*将描述符sockfd与server套接字地址结构中的协

24、议地址绑定*/ if (bind(sockfd,(struct sockaddr*)&server,sizeof(server) = -1); /*转换为被动套接字*/ listen(sockfd,BACKLOG); /*I/O复用*/ select_(sockfd); return 0;/end main/I/O复用static void select_(int listenfd) int connfd,sockfd; struct sockaddr_in cliaddr; socklen_t cliaddrlen; fd_set rset,allset; int maxfd,maxi; i

25、nt nready;/定义描述符个数 /*初始化客户连接描述符*/ int i; int clientsFD_SETSIZE; for (i = 0;i FD_SETSIZE;i+) clientsi = -1; /*初始化allset*/ FD_ZERO(&allset); /*设置listenfd为1*/ FD_SET(listenfd,&allset); maxfd = listenfd; maxi = -1; while(1)/死循环 rset = allset; /*获取可用描述符的个数*/ nready = select(maxfd+1,&rset,NULL,NULL,NULL);

26、/描述字个数,读 /*测试监听描述符是否准备好*/ if (FD_ISSET(listenfd,&rset) cliaddrlen = sizeof(cliaddr); /*接受客户端连接请求*/ if (connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen) = -1); /*将新的连接描述符添加到客户端数组中*/ for (i = 0;i FD_SETSIZE;i+) if (clientsi maxfd ? connfd : maxfd);/取最大值 maxi = (i maxi ? i : maxi);/取最大值

27、 if (-nready = 0) continue;/没有可读描述符 /*调用处理客户连接函数*/ deal_date(clients,maxi,&rset,&allset); /end while/end select_/处理客户连接static void deal_date(int *connfds,int num,fd_set *prset,fd_set *pallset) int i,n; char buffBUFFMAX;/数据缓存区 memset(buff,0,BUFFMAX);/将buff数组都赋值为0 time_t ticks; /*检查所有客户端数据*/ for (i =

28、0;i = num;i+) if (connfdsi 0) continue; /*测试客户描述符是否准备好*/ if (FD_ISSET(connfdsi,prset) /*接收客户端发送的信息*/ if(n = read(connfdsi,buff,BUFFMAX) = 0) close(connfdsi);/关闭连接 FD_CLR(connfdsi,pallset); connfdsi = -1; continue; /*发送当前系统时间*/ ticks=time(NULL);/获取当前系统时间 snprintf(buff,sizeof(buff),%.24srn,ctime(&tick

29、s);/将buff数组中的字符格式化为字符串存在buff上。 /*发送时间*/ write( connfdsi,buff,strlen(buff) ); /end if /end for/end deal_date客户端:#include #include #include #include #include #include #include #define BUFFMAX 1024#define IPADDRESS 127.0.0.1#define SERV_PORT 1234/主函数int main(int argc,char *argv) int sockfd; struct sockaddr_in server; /*生成TCP套接字*/ sockfd = socket(AF_INET,SOCK_STR

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1