您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 商业计划书 > Linux-基于socket的局域网聊天软件的设计与实现
提交日期:2012-06-20基于socket的局域网聊天软件的设计与实现1.实验目的《Linux操作系统课程设计B》是一门在课程《Linux操作系统与程序设计B》后独立开设的实验课程。这一门实验课程的开设目的是为了通过学生独立完成一个基于Linux平台的较大型应用程序,巩固课堂上学到的Linux平台上的编程规范、技术和技巧,培养学生的编写较大型程序的能力和提高学生综合应用素质。本课程设计实验主要围绕Linux平台上主流的基础技术展开,这些技术包括:Linux的进程、线程通信和同步技术;socket网络通信技术等,这些技术可以集中体现并应用在并发程序设计中。通过并发程序的设计与开发,培养学生底层软件开发的能力,并为将来从事UNIX/Linux平台开发、嵌入式开发等相对高端的软件开发工作打下基础。2.软件功能及模块划分本软件是一个linux下基于socket的聊天室程序,能让局域网内的用户通过该软件进行简单的文字通信。在此基础上增加了1.聊天室成员之间的发送私聊信息;2.当新的成员加入后能自动收取最近一段时间内的聊天上下文;3.用户能够查看历史聊天记录;4.软件界面基于Qt实现,图形化界面方便用户操作。主要模块划分:服务端:数据包发送和接受模块,聊天记录数据库读写模块,数据包处理模块,聊天记录查询模块客户端:数据包发送和接受模块,数据包处理模块,聊天记录查询模块,用户界面与展示模块1/333.设计与实现3.1系统概述与总体结构本系统采用CS架构,服务端采用固定的端口通信,每个客户端动态设置端口。客户端启动后向服务端告知自己所使用的端口号,以便可以双向通信,同时服务器负责为每个客户端分配一个唯一的ID(服务器的ID为1)客户端和服务端以及客户端和客户端之间采用约定的数据格式进行通信,以便接收方可以正确的解析命令和数据。数据包通用格式定义如下#defineMAX_UDP_SIZE1000structudp_packet{inttype;intsenderId;longsize;charcontent[MAX_UDP_SIZE];};type:表示该数据包的类型,直接决定content字段的含义senderId:该数据包的发送者的ID,size:整个数据包的数据长度content:数据包的内容,其数据格式由type决定。服务器和客户端接受到数据包后,根据type字段的值来解析content字段的数据,从而作出正确的处理和响应。所有的数据包类型以及对应的content字段的数据结构全部定义在define.h文件中[系统总体结构]接受数据包发送数据(可选)解析数据包服务端数据处理服务端初始化通知界面线程更新和显示数据接受数据包发送数据(可选)服务端初始化解析数据包客户端数据处理通知界面线程更新和显示数据客户端或用户主动发送消息Soceket通信2/33由上图可以看出,服务器和客户端程序在总体结构上相似。服务器和客户端的全部功在数据处理模块中实现,这也是整个程序的核心之处由于数据包的接受在单独的线程中完成,而界面采用Qt实现。因此在接受线程中采用QCoreApplication::postEvent()方法向界面线程发送通知事件,在界面窗口中通过重载customEvent()方法响应该通知,然后从Server中获取数据并显示。整个过程中涉及到线程同步和多线程安全问题,觉采用信号量和互斥量解决。3.2服务端的实现3.2.1服务总体实现与概述服务端的全部功能在类Server中实现,由于在整个系统中有且只有一个服务端出现,应此该类采用单例模式实现,通过Server::Instance()方法获得Server的一个实例,通过调用Init()函数完成服务端的初始化(包括信号量的初始化、数据库的连接、设置要发送事件通知的界面对象Object*),最后通过Start()方法创建socket,绑定端口,创建数据包接受线程,至此,完成服务器的启动部分代码:classServer{friendclassServerPacketProcessor;public:virtual~Server();staticServer*Instance();boolInit(QObject*mainWindow);boolStart();voidWaitForServerStop();protected:Server();void*ThreadStartRoutine(void*arg);private:staticvoid*ThreadRoutineTransponder(void*arg);voidpostEvent(QEvent::TypeeventType);staticServer*m_server;sockaddr_inm_localaddr;intm_sockfd;pthread_tm_thread;boolbCancel;pthread_mutex_tm_mutex_clients;pthread_mutex_tm_mutex_msgs;QObject*m_ui;。。。。。。3/33};Server.cpp#includeserver.hServer*Server::m_server=0;boolServer::Init(QObject*mainWindow){m_ui=mainWindow;bCancel=false;pthread_mutex_init(&m_mutex_clients,0);pthread_mutex_init(&m_mutex_msgs,0);returntrue;}Server*Server::Instance(){if(m_server==0)m_server=newServer();returnm_server;}boolServer::Start(){m_sockfd=socket(AF_INET,SOCK_DGRAM,0);if(m_sockfd==-1){cerrcreateudpsocketfailed!endl;returnfalse;}m_localaddr.sin_port=htons(SRV_PORT);m_localaddr.sin_family=AF_INET;m_localaddr.sin_addr.s_addr=htonl(INADDR_ANY);if(-1==bind(m_sockfd,(structsockaddr*)&m_localaddr,sizeof(m_localaddr))){cerrbindsocketfailed!endl;returnfalse;}if(!m_chatRecordMgr.ConnectDB(canghai,canghai,chat_record_schema)){cerrserverconnectdatebaseerror!endl;returnfalse;}if(0!=pthread_create(&m_thread,0,ThreadRoutineTransponder,0)){4/33cerrcreatethreadfailed!endl;returnfalse;}returntrue;}void*Server::ThreadRoutineTransponder(void*arg){returnServer::Instance()-ThreadStartRoutine(arg);}。。。。。。。3.2.2服务器发送数据模块的显示由于所有的数据包均以udp_packet结构包装,应此发送模块较简单voidServer::SendMsgTo(sockaddr_inclientaddr,constudp_packet*packet){sendto(m_sockfd,packet,packet-size,0,(structsockaddr*)&clientaddr,sizeof(clientaddr));}3.2.3服务器接受线程的实现服务端的接受线程负责接受客户端发来的数据,并且解析数据包,采取合适的动作。由于数据包的种类较多(随着功能的增加而增加),处理过程函数较为复杂,因此将数据包的处理过程封装在类ServerPacketProcessor的子类中,GetPacketProcessor()方法根据数据包的类型会创建合适的ServerPacketProcessor对象并返回线程函数和GetPacketProcessor方法的实现void*Server::ThreadStartRoutine(void*arg){while(!bCancel){udp_packetpacket;//定义缓冲区memset(&packet,0,sizeof(packet));sockaddr_inclientaddr;socklen_tlen=sizeof(clientaddr);size_tres=recvfrom(m_sockfd,&packet,sizeof(packet),0,(structsockaddr*)&clientaddr,&len);if(res==-1){cerrrecvfromerror...endl;5/33}//根据数据包的类型获得正确的处理方式ServerPacketProcessor*processor=GetPacketProcessor(packet.type);if(processor==0)continue;//处理数据包processor-ProcessPacket(&packet,clientaddr);deleteprocessor;}return0;}ServerPacketProcessor*Server::GetPacketProcessor(intpacket_type){switch(packet_type){caseCLIENT_ONLINE_REQUST://客户端上线请求{returnnewCltOnlinePacketProcessor(this);}caseGROUP_MSG_SEND://客户端发送群聊消息{returnnewGroupMsgPacketProcessor(this);}caseQUERY_USER_INFO://客户端查询其它用户信息{returnnewQueryUserInfoPacketProcessor(this);}caseQUERY_CHAT_RECORD://客户端查询聊天记录{returnnewQueryRecordPacketProcessor(this);}caseCLIENT_OFF_LINE://客户端下线{returnnewCltOfflinePacketProcessor(this);}default:return0;}}6/333.2.4服务器数据包处理模块的设计当接受线程收到数据包后要根据数据包的类型作出正确的处理和响应对应的消息类型和content字段的数据结构1.客户端上线请求#defineCLIENT_ONLINE_REQUST1structclient_info{charusername[20];//客户端用户昵称charhostname[30];//客户端的主机名shortclient_port;//客户端使用的通信端口};2.客户端发送群聊信息#defineGROUP_MSG_SEND4structgroup_msg_send{charcontent[MAX_MSG_SIZE];//消息内容};3.客户端查询其它用户信息#defineQUERY_USER_INFO6structquery_user{intuserId;//可以查询指定的ID的用户,0则表示查询所有的用户信息};4.客户端查询聊天记录#defineQUERY_CHAT_RECORD10structquery_chat_record{intby_begin_time;//查询方式,1表示离开始时间点最近的count条记录,0表示离结束时间点最近
本文标题:Linux-基于socket的局域网聊天软件的设计与实现
链接地址:https://www.777doc.com/doc-5977194 .html