《综合课程设计》设计报告-基于Socket的即时通讯系统.doc_第1页
《综合课程设计》设计报告-基于Socket的即时通讯系统.doc_第2页
《综合课程设计》设计报告-基于Socket的即时通讯系统.doc_第3页
《综合课程设计》设计报告-基于Socket的即时通讯系统.doc_第4页
《综合课程设计》设计报告-基于Socket的即时通讯系统.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

评阅教师评语:课程设计成绩考勤成绩实做成绩报告成绩总评成绩指导教师签名:综合课程设计设 计 报 告论文题目: 基于socket的即时通讯系统 学院(系): 电子信息与自动化学院 班 级: 721 学生姓名: 学号 指导教师: 时间: 2011 年 6月 7日 到 2011 年 6 月 17日一、 设计目的通过综合课程设计,使学生能够运用数字信号处理、信号与系统、通信原理、面向对象的程序设计、计算机通信网、通信协议开发及应用等课程的知识来设计一个基于socket的即时通讯系统,培养学生的动手能力以及分析问题、解决问题的能力。二、 设计内容一个基于socket的即时通讯系统的多人聊天软件三、 设计要求(一)基本要求1 熟练掌握面向对象的程序设计方法;2 实现点对点通讯,能进行文字对话传输,包括客户端与服务器端;3 能对系统参数进行配置。(二)提高要求1、实现文件、图片传输;2、语音对话(两人及两人以上);3、友好的对话界面。四、 设计原理1 tcp/ip简介 tcp/ip的历史要追溯到70年代中期,当时arpa为了实现异种网之间的互连(interconnection)与互通(intercommunication),大力资助网间网技术的研究和开发,于1977年到1979年推出目前形式的tcp/ip体系结构和协议规范.到今天,tcp/ip技术以及internet网间网已经为广大计算机工作者,机算机厂商和机算机用户所接受.据统计,到1990年,internet以包含遍布欧美的五千个活动网络,超过三十万台机算机.作为一种事实上的工标准,tcp/ip技术方兴未艾.2 tcp/ip的网络分层结构 对tcp/ip协议来说,tcp提供传输层服务,ip提供网络层服务.tcp/ip协议组(或internet协议组)的分层结构及其与osi模型的对应关系如图4所示.图中有关协议的名称及其基本含义如下: (1) tcp. 为传输控制协议(transmission control protocol).它是提供给用户进程的一个可靠的全双工字节流的面向连接的协议.大多数internet应用程序使用tcp.因为tcp使用ip,所以整个internet协议组也常称为tcp/ip协议组. (2) udp. 为用户数据报协议 (user datagram protocol). (3) icmp. 为网间报文控制协议 (internet control message protocol). (4) ip. 网间协议 (internet protocol). ip协议是为tcp,udp和icmp提供分组发送服务协议. (5) arp. 地址转换协议. (6) rarp. 反向地址转换协议.3 socket编程界面 (1) socket 原理 socket编程界面由4bsd unix首先提出,目的是解决网间网进程通信问题.socket接口为进程间通信提供了一种新的手段,它不但能用于同一机器中的进程之间的通信,而且支持网络通信功能.socket具有类型,反应了对用户透明的通信特性. 一个完整的socket连接用一个相关描述: 协议,本地地址,本地端口,远地地址,远地端口 socket 是面向客户-服务器模型而设计的,针对客户和服务器程序提供不同的socket系统调用. (2) socket系统调用 不管socket内部机制如何,它提供给应用程序员的最终界面是一组系统功能调用.下面,我们一一给出重要的socket系统调用. 1. 创建 socket - socket() 调用格式如下: sockid = socket (af,type,protocol) af : 地址族,指本socket所用地址类型. type : 类型,指创建socket的应用程序所希望的通信服务器类型. protocol : 协议,指本socket请求的协议. 2. 指定本地地址 - bind()调用 bind()将本地socket地址与所创建的socket联系起来,即将本socket地址赋予socket,以指定本地半相关.bind()的作用相当于给socket命名,调用格式为: bind (sockid,localaddr,addrlen) sockid : socket号. localaddr : 本地socket地址. addrlen : 地址长度. 3. 建立socket连接 - connect () 与 accept ()调用 这两个系统调用用于完成整个相关的建立.其中connect用于建立连接 .调用格为: connect (sockid,destaddr,addrlen) destaddr : 指向对方socket地址(信宿地址)结构的指针. accept : 用于面向连接的服务器,其调用格式为: newsock = accept (sockid,clientaddr,paddrlen) clientaddr : 指向客户socket地址指针. paddrlen : 客户socket地址长度. 4. listen() 调用 此调用用于面向连接服务器,表明它愿意接收连接,listen()在accept()之前调用,格式为: listen (sockid,quelen) quelen : 请求队列长度. 5. 发送数据 - write(),writev(),send()与sendto(),sendmsg() 用于socket数据发送的系统调用一共有五个,其中三个,write(),writev()和send()用于面向连接传输,其余两个用于无连接传输.面向连接的调用可以不指定信宿地址,而无连接的调用必须指定.假如无连接socket的双方均调用过connect(),可以认为是建立有连接的socket,也可以面向连接调用发送数据. 三个面向连接调用三者的格式大致相同: write (sockid,buff,bufflen) : 缓冲发送 writev (sockid,iovector,vectorlen) : 集中发送 send (sockid,buff,bufflen,flags) : 可控缓冲发送 其中buff指向发送缓冲区的指针,bufflen是发送缓冲区大小. 用于无连接数据发送的调用有两个: sendto (sockid,buff,bufflen,flags,dsadd,addrlen) sendmsg (sockid,message,flags):可控集中无连接发送. 6. 接收数据 - read(),readv(),recv()与recvfrom(),recvmsg() 接收数据与发送数据系统调用是一一对应的,两者参数的最大区别是,前者buffer是一个指针,其所指单元初值为欲读数据长度,调用后的值是实际读出的值.4 客户-服务器模型的socket实现框架 1)客户-服务器模型时序图 下图是面向连接客户-服务器模型的典型时序图 服务器 客户 socket() socket() bind() bind() listen() accept() 等待客户连接请求 阻塞 connect() read() write() 2)服务器socket地址的确定在客户-服务器模型中,所有的作用者都是客户首先发起的(如连接请求,服务请求等),因此客户必须要知道服务器socket地址,另外,客户调用服务器之前,可以在命令行中给出服务器所在主机的域名,根据域名可以获得服务器主机的地址,系统调用为:hp=gethostbyname(host).其中host可以是服务器主机域名,返回hp是一个指向主机地址结构的指针。五、 软件设计(附程序流程图、源程序清单)1. 程序流程图2.源程序清单void cchatroomdlg:dlgallinit()checkradiobutton(idc_radio_client, idc_radio_server, idc_radio_client);setdlgitemtext(idc_ip_addr, _t(); / 初始化ip地址为本机地址。setdlgitemtext(idc_connect_port, _t(5566); / 初始化端口。setdlgitemtext(idc_listen_port, _t(5566);enablewindow(idc_stop_client, false);enablewindow(idc_listen_port, false);enablewindow(idc_stop_server, false);enablewindow(idc_start_server, false);enablewindow(idc_static_listen_port, false); / 初始化按键启用or禁用。enablewindow(idc_sendmsg, false);bool cchatroomdlg:enablewindow(uint uid, bool benable)return getdlgitem(uid)-enablewindow(benable);void cchatroomdlg:extenddiaog(bool bshow)static crect m_dlgrectlarge(0, 0, 0, 0);static crect m_dlgrectsmall(0, 0, 0, 0);static crect m_grouprectlarge(0, 0, 0, 0);static crect m_grouprectsmall(0, 0, 0, 0); / 设置 窗口大小 if ( m_dlgrectlarge.isrectnull() ) getwindowrect(&m_dlgrectlarge);m_dlgrectsmall = m_dlgrectlarge;m_dlgrectsmall.right -= 220;:getwindowrect(getdlgitem(idc_frame)-getsafehwnd(), &m_grouprectlarge);m_grouprectsmall = m_grouprectlarge;m_grouprectsmall.right -= 220; / 设置 窗口 伸缩大小范围if ( bshow ) bshowall = true;setwindowpos(null, 0, 0, m_dlgrectlarge.width(), m_dlgrectlarge.height(), swp_nozorder | swp_nomove);:setwindowpos(getdlgitem(idc_frame)-getsafehwnd(), null, 0, 0, m_grouprectlarge.width(), m_grouprectlarge.height(), swp_nozorder | swp_nomove);elsebshowall = false;setwindowpos(null, 0, 0, m_dlgrectsmall.width(), m_dlgrectsmall.height(), swp_nozorder | swp_nomove);:setwindowpos(getdlgitem(idc_frame)-getsafehwnd(), null, 0, 0, m_grouprectsmall.width(), m_grouprectsmall.height(), swp_nozorder | swp_nomove);void cchatroomdlg:onbnclickednetset()if ( bshowall ) extenddiaog(false);elseextenddiaog(true); / 设置按键“网络设置”的作用void cchatroomdlg:onbnclickedstartserver()m_hlistenthread = createthread(null, 0, listenthreadfunc, this, 0, null);void cchatroomdlg:showmsg(cstring strmsg)m_msgedit.setsel(-1, -1);m_msgedit.replacesel(strmsg+_t(rn);void cchatroomdlg:removeclientfromarray(cclientitem in_item)for( int idx = 0; idx ) + strmsg;showmsg(strmsg);sendclientsmsg(strmsg);else if (m_bisserver = false) cstring strtmp = _t(张智超的客户端:) + strmsg;showmsg(strtmp);int isend = send(m_connectsock, (char *)strmsg.getbuffer(), strmsg.getlength()*sizeof(tchar), 0);strmsg.releasebuffer();elseafxmessagebox(_t(请您先进入聊天室!);setdlgitemtext(idc_input_msg, _t(); / socket 基本应用void cchatroomdlg:onbnclickedstartclient()m_hconnectthred = createthread(null, 0, connectthreadfunc, this, 0, null);void cchatroomdlg:sendclientsmsg(cstring strmsg, cclientitem *pnotsend)tchar szbufmax_buf_size = 0;_tcscpy_s(szbuf, max_buf_size, strmsg);for( int_ptr idx = 0; idx m_socket != m_clientarray.getat(idx).m_socket | pnotsend-hthread != m_clientarray.getat(idx).hthread |pnotsend-m_strip != m_clientarray.getat(idx).m_strip) send(m_clientarray.getat(idx).m_socket, (char *)szbuf, _tcslen(szbuf)*sizeof(tchar), 0);void cchatroomdlg:onenchangeinputmsg()cstring strmsg;getdlgitemtext(idc_input_msg, strmsg);if ( strmsg.isempty() ) enablewindow(idc_sendmsg, false);elseenablewindow(idc_sendmsg);void cchatroomdlg:stopclient()bshutdown = true;dword dwret = waitforsingleobject(m_hconnectthred, 1000);if ( dwret != wait_object_0 ) terminatethread(m_hconnectthred, -1);closesocket(m_connectsock);m_hconnectthred = null;m_connectsock = invalid_socket;m_bisserver = -1;bshutdown = false;void cchatroomdlg:stopserver()uint ncount = m_clientarray.getcount();handle *m_phandles = new handlencount+1;m_phandles0 = m_hlistenthread;for( int idx = 0; idx ncount; idx+ ) m_phandlesidx+1 = m_clientarray.getat(idx).hthread;bshutdown = true;dword dwret = waitformultipleobjects(ncount+1, m_phandles, true, 1000);if ( dwret != wait_object_0 ) for( int_ptr i = 0; i getwindowrect(&mrect);pt = mrect.bottomright();pt.y = mrect.top+10;mmenu.loadmenu(idr_menu1);pmenu = mmenu.getsubmenu(0);pmenu-trackpopupmenu(tpm_leftalign | tpm_rightbutton, pt.x, pt.y, this);bool cchatroomdlg:traymyicon(bool badd)bool bret = false;notifyicondata tnd;tnd.cbsize = sizeof(notifyicondata);tnd.hwnd = getsafehwnd();tnd.uid = idr_mainframe;if ( badd = true ) tnd.uflags = nif_message | nif_icon | nif_tip;tnd.ucallbackmessage = wm_trayicon_msg;tnd.hicon = loadicon(afxgetinstancehandle(), makeintresource(idr_mainframe);_tcscpy_s(tnd.sztip, sizeof(tnd.sztip), _t(聊天室v1.0);showwindow(sw_minimize);showwindow(sw_hide);bret = shell_notifyicon(nim_add, &tnd);elseshowwindow(sw_showna);setforegroundwindow();bret = shell_notifyicon(nim_delete, &tnd);return bret;void cchatroomdlg:onmenutrayinco()traymyicon();lresult cchatroomdlg:ontraycallbackmsg(wparam wparam, lparam lparam)switch(lparam)case wm_rbuttonup:cmenu mmenu, *pmenu = null;cpoint pt;mmenu.loadmenu(idr_menu2);pmenu = mmenu.getsubmenu(0);getcursorpos(&pt);setforegroundwindow();pmenu-trackpopupmenu(tpm_leftalign | tpm_rightbutton, pt.x, pt.y, this);break;case wm_lbuttondblclk:showwindow(sw_restore);setforegroundwindow();traymyicon(false);break; 3. 附录:课程设计中要用到的winsock函数wsastartup初始化socket库wsacleanup结束socket库的使用socket为所要进行的网络通信建立标识符connect连接到远程主机closesocket结束通信,关闭标识符bind将ip地址、tcp端口号与套接字标识符绑定listen将接受套接字置于被动模式,将服务器置于侦听状态,并指定允许的连接数accept接受下一个呼入的连接recv接收传入的tcp数据recvfrom接收传入的udp数据select在指定的套接字集准备好接收数据前一直等待send发送tcp数据sendto发送udp数据shutdown释放tcp连接getpeername从套接字中获取对等方的端口地址setsocketopt获取当前套接字的可变选项gethostbynameinet_addr把域名转换成网络ip地址把用点分十进制表示的ip地址转换成网络ip地址getservbynamegetprotobyname获得服务器的端口号把tcp、udp转换成相应的服务号码(interger)六、 调试过程测试的目的是为了发现功能是否达到,或者是否有更多的缺陷。当两个客户端在建立连接时,出现过程序假死异常。分析代码发现,线程调度出错,接收消息线程th还未创建和启动,监听线程wait已经被销毁了。修改代码,给出两种解决办法:(1)在th线程的执行方法中,将wait线程销毁;在th线程销毁前,重新开启wait线程。(2)wait线程不销毁。设置一bool类型变量isconnected,当已经建立连接后,isconnected=true,若再有其他的连接请求到达,自动将其他连接请求拒绝。连接断开后,重置isconnected=false,将处理移交给用户。我采用了第一种方法,调试之后,问题解决。在程序退出时,常常发生错误,异常退出,造成表面上看程序已结束,但却仍然驻留在内存中的现象。经过反复分析代码,最终确定问题出在程序退出处理流程上,通过修改和调试,问题解决。软件图示七、 实验结果分析整个开发过程中,共历经多次相互断开、连接测试,聊天模块终于可以正常运行。借助在文本聊天模块开发过程中积累的经验,较顺利的完成了文件传输模块的开发。通过在总集成后的程序的各个流程中添加消息提示框显示程序内部数据、对象的状态,并插入断点进行单步跟踪发现各模块工作正常,数据也未发生异常现象。(1)程序启动之后就能看到当前哪些机器在线,哪些可以与之进行对等通信。(2)一旦有某个网内的机器上线了,要有即时通知,并能及时更新用户界面中的用户列表。(3)当双击某个列表项的时候,要弹出聊天对话框,可以在其中编辑要发送的聊天信息,并进行发送。(4)聊天界面要人性化,下面是发送框,上面有已有聊天记录,并借助滚动条看到当次所有的聊天记录。(5)当有远程用户向本机发送文件的时候,要弹出一个消息提示框,提示本机用户,可以选择接收或者拒绝。(6)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论