课 设计名称:仿学生姓名:班 级:组织单位:指导教师:时 间:程 设 计 报 告
QQ通信系统 2013.6.3----2013.6.23
课程设计
一、 摘要
即时通信,由于具有实时性、跨平台性、成本低、效率高等优点而受到广泛的使用。设计并实现一个能够处理多用户进行实时,安全的即时通信系统具有较强的现实意义。本文设计并实现了在linux环境里基于局域网内的简单即时通信系统,系统采用C/S模式,底层通信通过socket套接字接口实现,能进行简单实时通信并能实现文件的传输。
关键字:即时通信 TCP/UDP Linux 文件传输
二、 需求分析
局域网仿qq通信系统能实现即时通信,并且通讯采用TCP/UDP协议。Socket是基于TCP/IP协议之上的一个接口规范,它为应用层之间的通信提供了保障。Socket适用于客户/服务器模式的网络应用程序设计,在使用面向连接模式时,使用TCP协议作为通信协议,为应用程序提供面向连接的服务。
用Socket进行网络通信时,需要在客户端和服务器端分别创建一个Socket,服务器端创建成功以后在特定的端口上监听客户端的连接请求。如果有客户端的连接请求到来,则成功建立一个连接后,客户端和服务器端就可以互相进行通信了。但只能是和客户端进行点对点的通信,即服务器只允许有一个客户端的连接,如果有连接请求到达时,服务器端需要再创建一个新的Socket与客户端进行通信,而原来的那个Socket仍处于监听状态,等待新的客户的连接请求。
三、 概要设计
程序必须建立一个Socket,按照要求配置此Socket,也就是说程序要么将此Socket连接到远方的主机上,要么给此Socket指定一个本地协议端口。程序必须按要求通过此Socket发送和接收数据,程序必须关闭此Socket。 客户端:
——创建客户端套接字(CREATE); ——开始数据传输(SEND、RECEIVE); ——关闭套接字(CLOSESOCKET); 服务器端:
——创建服务器端套接字(CREATE); ——服务器端套接字进行信息绑定(BIND),并开始监听连接(LISTEN); ——接受来自客户端的连接请求(ACCEPT),并创建接收进程; ——开始数据传输(SEND、RECEIVE); ——关闭套接字(CLOSESOCKET)。
四、 详细设计
下面是实现TCP通信和UDP通信的流程
1
课程设计
TCP通信程序的逻辑框图
Server端:S=socket()Client端:Bind(s,(struct sockaddr far *)&lAddr, sizeof(lAddr))S=socket()Listen()Connect()阻塞,等待客户连接连接请求Accept()Send()Recv()Recv()阻塞,等待客户连接服务请求阻塞,等待服务数据处理服务请求服务应答Send()处理数据Y继续Y继续NNClosesocket(s)Closesocket(s)
2
课程设计
UDP通信程序的逻辑框图
Server端:Client端:s=socket()s=socket()bind(s,(struct sockaddr far bind(s,(struct sockaddr far *)&lAddr, sizeof(lAddr))*)&lAddr, sizeof(lAddr))Recv(s,Msg, 80,0)阻塞,等待客户请求sendto(S,Msg,strlen(Msg), 0,(struct sockaddr far *)&rAddr, l)处理服务请求Recv(s,Msg, 80,0)sendto(S,Msg,strlen(Msg), 阻塞,等待服务数据0,(struct sockaddr far *)&rAddr, l)Y处理数据继续N继续YClosesocket(s)NClosesocket(s)五、 源程序和运行结果清单 #include #include #include void Menu() { 3 课程设计 printf(\"\\|================================================ \\n\"); printf(\"\\|================================================ \\n\"); printf(\"\\| 欢迎进入系统 \\n\"); printf(\"\\|================================================ \\n\"); printf(\"\\| 1.UDP通信 \\n\"); printf(\"\\| 2.TCP通信 \\n\"); printf(\"\\| 3.文件传输 \\n\"); printf(\"\\| 4.exit \\n\"); printf(\"\\|================================================\\n\"); } void *recver(void* data) { int fd1; //文件描述符 struct sockaddr_in addr1; struct sockaddr_in addr_send1; //发送者地址对象 socklen_t len1; //socket_t类型的变量len int r1; //结果 char buf1[200]; //1.socket fd1=socket(AF_INET,SOCK_DGRAM,0); /*AF是网络传输,so..是udp报文传输,0是自动比配*/ if (fd1==-1) printf(\"socket err:%m\\n\"),exit(-1); printf(\"A socket ok\\n\"); //2.bind addr1.sin_family=AF_INET; //全大写模式的是宏状态 addr1.sin_port=htons(9999); inet_aton(\"127.0.0.1\ r1=bind(fd1,(struct sockaddr*)&addr1,sizeof(addr1)); if(r1==-1) printf(\"A bind err:%m\\n\"),exit(-1); printf(\"A bind ok\\n\"); //3.recv while(1) { len1=sizeof(addr_send1); r1=recvfrom(fd1,buf1,sizeof(buf1)-1,0,(struct sockaddr*)&addr_send1,&len1); /*从fd里取值给buf,接收从接收者送来到信息放到len来*/ if(r1>0) { buf1[r1]=0; 4 课程设计 printf(\"收到来自IP=%s,PORT=%hu的信息,内容如下:\\n%s\\n\ inet_ntoa(addr_send1.sin_addr), ntohs(addr_send1.sin_port), buf1); //ntoa网络字节序转化为网络字符串 } if(r1==0) //对方关闭 { printf(\"关闭\\n\"); break; } if(r1<0) { printf(\"网络链接失败\\n\"); break; } } //4.close close(fd1); } void *sender() { int fd1; //文件描述符 struct sockaddr_in addr1; int r1; //结果 char buf1[200]; //1.socket fd1=socket(AF_INET,SOCK_DGRAM,0);/*AF是网络传输,so..是udp报文传输,0是自动僻配*/ if (fd1==-1) printf(\"socket err:%m\\n\"),exit(-1); printf(\"A socket ok\\n\"); //2.发送信息目标addr addr1.sin_family=AF_INET; //全大写模式的是宏状态 addr1.sin_port=htons(9999); inet_aton(\"127.0.0.1\ //3.recv while(1) { 5 课程设计 scanf(\"%s\ r1=sendto(fd1,buf1,strlen(buf1),0,(struct sockaddr*)&addr1,sizeof(addr1)); /*strlen 确定字符串里有效字符长度*/ } //4.close close(fd1); } int main() { int q; Menu(); printf(\"option:\\n\"); scanf(\"%d\ switch (q) { case(1): { printf(\"UDP通信\"); pthread_t tid; //声明整型tid pthread_t tid2; pthread_create(&tid,0,recver,NULL); /*在线/进程当中创建线程,传地址是为了改变 tid是指向线程的标识符的指针,0为设置线程的属性,run线程运行函数的起始地址,传给函数到参数*/ pthread_create(&tid2,0,sender,NULL); while(1);break; } case(2): { printf(\"TCP通信\\n\"); if(fork()) { int serverfd; //服务器文件描述符 int cfd; //客户端文件描述符 struct sockaddr_in sadr; //服务器地址 struct sockaddr_in cadr; //客户端地址 socklen_t len; int r; int a; char buf[200]; //1.socket 6 课程设计 serverfd=socket(AF_INET,SOCK_STREAM,0); if(serverfd==-1) printf(\"socket err%m\\n\"),exit(-1); printf(\"server socket ok!\\n\"); sadr.sin_family=AF_INET; sadr.sin_port=htons(9997); inet_aton(\"127.0.0.1\ //2.bind r=bind(serverfd,(struct sockaddr*)&sadr,sizeof(sadr)); if(r==-1) printf(\"server bind err%m\\n\"),exit(-1); printf(\"server bind ok\\n\"); //3.listen r=listen(serverfd,10); //监听服务器 if(r==-1) printf(\"server listen err%m\\n\"),exit(-1); printf(\"server listen ok\\n\"); //4.accept len=sizeof(cadr); cfd=accept(serverfd,(struct sockaddr*)&cadr,&len); printf(\"有人链接%d,IP:%s,Port:%u\\n\ inet_ntoa(cadr.sin_addr),ntohs(cadr.sin_port)); //5.action while(1) { r=recv(cfd,buf,sizeof(buf),0); buf[r]=0; if(r>0) printf(\"收到数据::%s\\n\ if(r==0) { printf(\"链接断开\\n\"); break; } if(r<0) { printf(\"网络故障\\n\"); break; } } close(cfd); close(serverfd); return; 7 课程设计 } else { int fd; struct sockaddr_in addr; int r; int s=0; char buf[200]; //1.socket fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) printf(\"1:%m\\n\"),exit(-1); printf(\"建立socket成功!\\n\"); //2.connect addr.sin_family=AF_INET; addr.sin_port=htons(9997); inet_aton(\"127.0.0.1\ r=connect(fd,(struct sockaddr*)&addr,sizeof(addr)); if(r==-1) printf(\"2:%m\\n\"),exit(-1); printf(\"连接服务器成功!\\n\"); //3.send while(1) { bzero(buf,sizeof(buf)); printf(\"请输入要传送的数据\\n\"); scanf(\"%s\ // if(buf[0]=0) break; r=send(fd,buf,strlen(buf),0); if(r>0) printf(\"发送成功\\n\"),sleep(2); //发送进程休息3秒 等待接收进程显示收到的数据 if(r==0) { printf(\"链接断开\\n\"); break; } if(r<0) { printf(\"网络故障\\n\"); break; } 8 课程设计 } close(fd); return; } break; } case(3): { printf(\"文件传输\"); if(fork()) { int sfd3,cfd3,ffd3; int r3; int len3; char buf3[200]; char filename[100]; struct sockaddr_in dr; //1.socket sfd3=socket(AF_INET,SOCK_STREAM,0); if(sfd3==-1) printf(\"server socket err%m\\n\"),exit(-1); printf(\"server socket ok\\n\"); //2.bind dr.sin_family=AF_INET; dr.sin_port=htons(9995); dr.sin_addr.s_addr=inet_addr(\"127.0.0.1\"); r3=bind(sfd3,(struct sockaddr*)&dr,sizeof(dr)); if(r3==-1) printf(\"server bind err%m\\n\"),exit(-1); printf(\"server bind ok\\n\"); //3.listen r3=listen(sfd3,10); if(r3==-1) printf(\"server listen err:%m\\n\"),exit(-1); printf(\"server listen ok!\\n\"); //4.accept cfd3=accept(sfd3,0,0); if(cfd3==-1) printf(\"server accept err:%m\\n\"),exit(-1); printf(\"server accept ok!\\n\"); //action r3=recv(cfd3,&len3,sizeof(len3),MSG_WAITALL); printf(\"文件名长度是:%d\\n\ r3=recv(cfd3,filename,len3,MSG_WAITALL); printf(\"传递到文件是:%s\\n\ ffd3=open(filename,O_RDWR|O_CREAT,0666); 示自己,2是其他,3是工作组 //第一个6表9 课程设计 while(1) { r3=recv(cfd3,&len3,sizeof(len3),MSG_WAITALL); if(len3==0) break; r3=recv(cfd3,buf3,len3,MSG_WAITALL); write(ffd3,buf3,len3); } close(ffd3); close(cfd3); close(sfd3); printf(\"————恭喜文件接受完毕————\\n\"); } else { int sfd3,ffd3; int r3; int size; int len3; int buf3[100]; struct sockaddr_in dr; char filename[]=\"abc.txt\"; //1.socket sfd3=socket(AF_INET,SOCK_STREAM,0); if(sfd3==-1) printf(\"server socket err%m\\n\"),exit(-1); printf(\"server socket ok\\n\"); //2.connect dr.sin_family=AF_INET; dr.sin_port=htons(9995); inet_aton(\"127.0.0.1\ r3=connect(sfd3,(struct sockaddr*)&dr,sizeof(dr)); if(r3==-1) printf(\"connect err%m\\n\"),exit(-1); printf(\"connect ok\\n\"); //3.open file ffd3=open(filename,O_RDONLY); if(ffd3==-1) printf(\"open err%m\\n\"),exit(-1); printf(\"open ok\\n\"); //4.send filename len3=strlen(filename); //获得文件名长度 r3=send(sfd3,&len3,sizeof(len3),0); r3=send(sfd3,filename,len3,0); 10 课程设计 if(r3==-1) printf(\"send err%m\\n\"),close(ffd3),close(sfd3),exit(-1); printf(\"filename send ok\\n\"); //5.send filedata while(1) { size=read(ffd3,&size,sizeof(size)); if(size==0) break; if(size==-1) break; if(size>0) break; { r3=send(sfd3,&size,sizeof(size),0); if(r3==-1) break; r3=send(sfd3,buf3,size,0); if(r3==-1) break; } } size=0; r3=send(sfd3,&size,sizeof(size),0); close(ffd3); close(sfd3); } break; } case(4): { exit(0); } default:printf(\"error\\n\"); } return 0; } //发送截取文件到长度//发送截取文件到内容11 课程设计 执行结果如下 12 课程设计 六、 总结 Xxx:通过三周的课程设计我掌握了许多以前没有接触过的内容,同时也掌握了许多有用的知识。这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。 Xxx:本学期的最后时间里我们进行了为期9天的仿qq通信系统的课程设计,在此期间我和队友们一起互相学习、讨论,终于圆满完成此次课程设计。首先指导老师很幽默,讲课方法独特,很有吸引力,让我们不会感觉到累和困。起初指导老师让我们先回顾一些简单的小程序算是唤起我们的记忆,他会让我们自己动手去写,不给我们代码,这样可以锻炼我们,同时也可以克服依赖的坏习惯。后来老师就讲解通讯系统该怎么去编写。户端,服务器端,线程,进程,TCP、UDP、SOCKET等一些名词老师都详细讲解。 期间我们遇到很多难以修改的错误,要么请求老师指导,要么百度,大家都一一解答出来了,九天时间天天对着电脑应该很累,很疲惫,但是我们都坚持下来,认真学习。最后真心地感谢老师和学校给我们提供了平台让我们把理论和实践相结合,各位指导老师你们辛苦了。 Xxx:回顾起此次课程设计,至今我仍感慨颇多,的确,从从拿到题目到完成整个编程,从理论到实践,在大约两个学期的日子里,可以学到很多很多的的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。在设计的过程中遇到问题,可以说得是困难重重,由于c/c++都很久没有复习了,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,特别是结构体,通过这次课程设计之后,一定把以前所学过的知识重新温故。 Xxx:课程设计结束了,在这次的课程设计中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在设计过程中,与同学分工设计,和同学们相互探讨,相互学习,相互监督。学会了合作,学会了运筹帷幄,学会了宽容,学会了理解,也学会了做人与处世。课程设计是我们专业课程知识综合应用的实践训练,着是我们迈向社会,从事职业工作前一个必不少的过程.”千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义.我今天认真的进行课程设计,学会脚踏实地迈开这一步,就是为明天能稳健地在在这次设计过程中,,体会了学以致用、突出自己劳动成果的喜悦心情,从中发现自己平时学习的不足和薄弱环节,从而加以弥补。 在此感谢我们的老师.,老师严谨细致、一丝不苟的作风一直是我工作、学习中的榜样;老师循循善诱的教导和不拘一格的思路给予我无尽的启迪;这次设计的每个实验细节和每个数据,都离不开老师您的细心指导。而您开朗的个性和宽容的态度,帮助我能够很顺利的完成了这次课程设计。 13 因篇幅问题不能全部显示,请点此查看更多更全内容