网络程序设计linux服务器课程设计报告文档格式.docx
《网络程序设计linux服务器课程设计报告文档格式.docx》由会员分享,可在线阅读,更多相关《网络程序设计linux服务器课程设计报告文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
4.掌握使用select实现I/O复用。
5.掌握守护进程的编写。
1.2实验要求
1.认真阅读和掌握本实验的相关的知识点。
2.上机编写并运行程序。
1.3实验内容
实现一个并发、IO复用的守护进程时间服务器,要求当客户端向服务器发送“what’stime?
”字符串时,服务器回应当时的系统时间字符串。
1.4小组分工
成员
负责内容
梁小龙
任务书、课程设计资料查询、代码测试
杨国浩
服务器端程序I/O复用模块分析与设计
杨天
客户端clinet整体程序、课程设计报告
豆全胜
服务器端守护进程模块与主函数模块
第2章课程设计分析及内容
2.1所用知识点
2.1.1套接字函数
客户端所用函数:
socket()函数、connect()函数、send()函数、recv()函数,close()函数。
服务器端所用函数:
bind()函数、socket()函数、listen()函数、accept()函数、send()函数、accept()函数、recv()函数、close()函数。
2.1.2守护进程
守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。
它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
守护进程常常在系统引导装入时启动,在系统关闭时终止。
Linux系统有很多守护进程,大多数服务都是通过守护进程实现的。
每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。
但是守护进程却能够突破这种限制,它从被执行开始运转,直到整个系统关闭时才退出。
如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。
2.1.3I/O复用
I/O复用调用select或poll,并在该函数上阻塞,等待数据报套接口可读;
当select返回可读条件时,调用recvfrom将数据报拷贝到应用程序缓冲区中。
主要应用:
(1)客户程序需要同时处理交互式的输入和服务器之间的网络连接。
(2)客户端需要对多个网络连接作出反应。
(3)TCP服务器需要同时处理多个处于监听状态和多个连接状态的套接字。
(4)服务器需要处理多个网络协议的套接字。
(5)服务器需要同时处理不同的网络服务和协议。
2.1.4并发服务器
不同于顺序服务器,并发服务器就要能在一个时间为多个客户端提供服务。
例如,一个聊天服务器可能服务一个特定的客户端数小时──在停止为这个客户端服务之前服务器不能等待,除非是在等待一下个客户端到来之前的间隙才能等待。
第3章课程设计的实现
3.1程序运行步骤
对于服务器端而言,由于它是一个守护进程所以只要做到接收信息并且存储在一个数组中即可而不必在前台显示,对于客户端必须有信息的发送和接收。
服务器端必须对来自客户端的信息加以判断。
如果接收到的字符串与“what’s_time?
”字符串行匹配那么则返回给客户端一个系统的时间信息,否则返回给客户端“Inputerror”的字符串。
如下图所示:
图3-1连接流程图
3.2客户端主要函数
3.2.1socket()函数
socket()函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源。
创建一个套接口,代码如下:
#include<
winsock.h>
SOCKETPASCALFARsocket(intaf,inttype,intprotocol);
Af是一个地址描述。
目前仅支持AF_INET格式,也就是说ARPAInternet地址格式,Type是新套接口的类型描述,protocol:
套接口所用的协议,如调用者不想指定,可用0指定,表示缺省。
3.2.2connect()函数
本函数用于创建与指定外部端口的连接。
s参数指定一个未连接的数据报或流类套接口。
如套接口未被捆绑,则系统赋给本地关联一个唯一的值,且设置套接口为已捆绑。
请注意若名字结构中的地址域为全零的话,则connect()将返回WSAEADDRNOTAVAIL错误。
返回值:
若无错误发生,则connect()返回0。
否则的话,返SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
创建一个连接,代码如下:
//调用套接字
intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);
s是标识一个未连接套接口的描述字。
Name是欲进行连接的端口名。
Namelen是名字长度。
3.3服务端函数
3.3.1send函数和recv函数
1.send函数
intsend(SOCKETs,constcharFAR*buf,intlen,intflags);
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。
客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。
第一个参数指定发送端套接字描述符。
第二个参数指明一个存放应用程序要发送数据的缓冲区。
第三个参数指明实际要发送的数据的字节数。
第四个参数一般置0。
2.recv函数
intrecv(SOCKETs,charFAR*buf,intlen,intflags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。
第一个参数指定接收端套接字描述符。
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据。
第三个参数指明buf的长度。
3.3.2close()函数
close函数用于关闭套接字,并立即返回到进程。
关闭后的套接字描述符不能再接收和发送数据,再不能作为函数send()或recv()的参数。
如果套接字描述符访问计数在调用close后大于0(在多个进程共享同一个套接字的情况下),则不会引发TCP终止序列(即不会发送FIN分节)。
3.3.3select函数
select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。
3.4创建守护进程
创建步骤:
使进程在后台运行
②脱离控制终端,登录会话和进程组(创建新会话)
③禁止进程重新打开控制终端
④关闭所有文件描述符
⑤改变当前工作目录
⑥重设权限掩码
⑦处理SIGCHLD信号
心得体会
经过两周的课程设计,我们对Linux有了更深的体会,意识到只有动手去操作才能真的掌握它。
同样也对服务器有了多重的认识,认识到其在生活中的重要性,和我们的生活密不可分。
时间服务器更是重中所重,时间的重要性越来越大,时间服务器作为时间的核心其重要性已经不言而喻,且开发成本较小,用时较少,易于开发。
不仅为我们以后的程序生涯打好基础,也能增加我们对编写程序的兴趣。
这次之后,我们小组还算是比较默契的。
没想到这项看起来不需要多少技术的工作却是非常需要耐心和精力,在两周后的今天我已明白课程设计对我来说的意义,它不仅仅是让我们把所学的理论知识与实践相结合起来,提高自己的实际动手能力和独立思考的能力,更重要的是同学间的团结,虽然我们这次花去的时间比别人多,但我相信我们得到的也会更多。
在这次课程设计中,我们运用到了以前所学的专业课知识,比如并发服务器原理,I/O复用技术,守护进程的创建。
正如孔子所说:
“温故而知新”,我们在开发的过程中有时会遇到问题,等到解决之后,发现自己知道了更多的东西,对知识点有了更深刻的理解。
这也激发了我今后努力学习的兴趣,我想这将对我以后的学习产生积极的影响。
其次,这次课程设计让我充分认识到团队合作的重要性,只有分工协作才能保证整个项目的有条不絮。
另外在课程设计的过程中,当我们碰到不明白的问题时,指导老师总是耐心的讲解,给我们的设计以极大的帮助,使我们获益匪浅。
因此非常感谢老师的教导。
附录一系统界面
附录二程序代码
客户端程序:
#include<
stdio.h>
stdlib.h>
string.h>
unistd.h>
sys/socket.h>
netinet/in.h>
netdb.h>
#definePORT1234
#defineMAXDATASIZE100
#defineMAXLINE100
intmain(intargc,char*argv[])
{
intfd,numbytes;
charbuf[MAXDATASIZE],sendline[MAXLINE];
structhostent*he;
structsockaddr_inserver;
if(argc!
=3){
fprintf(stderr,"
usage:
%s<
IP>
addressandmyport\n"
argv[0]);
exit
(1);
}
if((he=gethostbyname(argv[1]))==NULL){
perror("
gethostbynameerror."
);
exit(-1);
if((fd=socket(AF_INET,SOCK_STREAM,0))==-1){
Createsocketfailed"
elseprintf("
ConnectSuccess!
\n"
bzero(&
server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr=*((structin_addr*)he->
h_addr);
if(connect(fd,(structsockaddr*)&
server,sizeof(structsockaddr))==-1){
Binderror."
if((numbytes=recv(fd,buf,MAXDATASIZE,0))==-1){
recverror."
buf[numbytes]='
\0'
;
printf("
ServerMessage:
%s\n"
buf);
close(fd);
}服务器端程序:
syslog.h>
signal.h>
sys/types.h>
sys/select.h>
include<
arpa/inet.h>
#defineBACKLOG5
#defineMAXLINE255
#defineMAXFD64
voiddemon_init(constchar*pname,intfacility)
inti;
pid_tpid;
if((pid=fork())!
=0)
exit(0);
setsid();
signal(SIGHUP,SIG_IGN);
chdir("
/"
umask(0);
for(i=0;
i<
MAXFD;
i++)
close(i);
openlog(pname,LOG_PID,facility);
}
intmain(intargc,char**argv)
intlistenfd,connfd;
socklen_taddrlen,len;
structsockaddr_inclient_addr;
charbuff[MAXLINE];
time_tticks;
client_addr,sizeof(client_addr));
server.sin_port=htons(1234);
server.sin_addr.s_addr=htonl(INADDR_ANY);
demon_init(argv[0],0);
if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
syslog(LOG_NOTICE|LOG_LOCAL0,"
socketerror"
if(bind(listenfd,(structsockaddr*)&
server,sizeof(structsockaddr))==-1)
if(listen(listenfd,BACKLOG)==-1)
for(;
){
len=sizeof(client_addr);
connfd=accept(listenfd,&
client_addr,&
len);
ticks=time(NULL);
snprintf(buff,sizeof(buff),"
%.24s\r\n"
ctime(&
ticks));
inta;
if((a=write(connfd,buff,strlen(buff)))==-1)
{
syslog(LOG_NOTICE|LOG_LOCAL0,"
writeerror"
exit(0);
}
intfd_A[BACKLOG];
intconn_amount;
intret;
inti,new_fd;
fd_setfdsr;
intmaxsock;
structtimevaltv;
conn_amount=0;
maxsock=listenfd;
while
(1){
FD_ZERO(&
fdsr);
FD_SET(listenfd,&
tv.tv_sec=30;
tv.tv_usec=0;
for(i=0;
i<
BACKLOG;
i++){
if(fd_A[i]!
=0){
FD_SET(fd_A[i],&
ret=select(maxsock+1,&
fdsr,NULL,NULL,&
tv);
if(ret<
0){
select"
break;
}elseif(ret==0){
timeout\n"
continue;
conn_amount;
if(FD_ISSET(fd_A[i],&
fdsr)){
ret=recv(fd_A[i],buff,sizeof(buff),0);
=0){
client[%d]close\n"
i);
close(fd_A[i]);
FD_CLR(fd_A[i],&
fd_A[i]=0;
}else{
MAXLINE)
memset(&
buff[ret],'
1);
client[%d]send:
%s\n"
i,buff);
if(FD_ISSET(listenfd,&
new_fd=accept(listenfd,(structsockaddr*)&
client_addr,&
if(new_fd<
accept"
if(conn_amount<
BACKLOG){
fd_A[conn_amount++]=new_fd;
newconnectionclient[%d]%s:
%d\n"
conn_amount,
inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if(new_fd>
maxsock)
maxsock=new_fd;
else{
maxconnectionsarrive,exit\n"
send(new_fd,"
bye"
4,0);
close(new_fd);
}