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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

计算机网络课设基于TCP协议编程的网络聊天室.docx

1、计算机网络课设基于TCP协议编程的网络聊天室基于TCP协议编程的网络聊天室设计内容:基于TCP协议编程的方式,编写程序模拟网络聊天室的运行过程。设计要求:1. 采用C/S模式,基于TCP协议编程的方式,使得各个用户通过服务器转发实现聊天的功能。2. 分为两大模块:客户端模块和服务器端模块。3. 客户端模块的主要功能:1)登陆功能:用户可以注册,然后选择服务器登入聊天室。2)显示用户:将在线用户显示在列表中。3)接收信息:能接收其他用户发出的信息。4)发送信息:能发出用户要发出的信息。4.服务器端模块的主要功能:1)检验登陆信息:检查登陆信息是否正确,并向客户端返回登陆信息,如信息正确。就允许用

2、户登陆。2)显示在线状态:将该用户的状态发给各在线用户。3)转发聊天信息:将消息转发给所有在线的用户。5. 编程语言不限。一、 需求分析此程序主要分为两部分:服务器端和客户端。服务器端用于提供一个网络端口,等待客户端发出请求,登录到此服务端,然后进行网络通讯和消息的转发;客户端可通过服务器端的IP地址发送连接请求,然后登陆聊天室。在服务器端的成员列表栏中会显示在线的所有人名单,有人退出聊天室,成员列表会自动除名。整个程序的主体使用了CSocket类的方法,实现了网络通讯聊天。整个程序设计为两个部分:服务器(SpeakerServer)和客户端 (SpeakerClient)。 多人聊天的关键在

3、于要将每个客户端发送过来的消息分发给所有其他客户端,为了解决这个问题,在服务器程序中建立一个套接口链表,用来保存所有与客户端建立了连接的服务端口。设计原理:服务器通过socket()系统调用创建一个Socket数组后(设定了接受连接客户的最大数目),与指定的本地端口绑定bind(),就可以在端口进行侦听listen()。如果有客户端连接请求,则在数组中选择一个空socket,将客户端地址赋给这个socket,然后登陆成功的客户就可以在服务器上聊天了。客户端程序相对简单,只要建立一个socket与服务器端连接,成功后通过这个socket来发送和接收就可以了。服务器端功能:1、 初始化socket

4、,创建服务器端。2、 维护一个链表,保存所有用户的IP地址,端口信息。3、 接受用户传送来的聊天信息,然后向链表中的所用用户转发。4、 接受用户传送来的连接判断命令,并向用户发出响应命令。客户端功能:客户端界面上的两个文本框,一个用于显示接受的聊天信息,一个用来接受用户输入的聊天信息。当按下“发送”按钮时将信息发送给服务器。一、 概要设计:服务器 客户端(设计流程图)二、 详细设计:服务器端:1、启动服务器代码:/服务器启动时,先创建套接字并绑定端口,再监听此端口。void CSpeakerServerDlg:OnBnClickedStart() UINT uPort = GetDlgItem

5、Int(IDC_PORT); /创建套接字 if ( !m_TCPSocketListen.Create(uPort) ) m_TraceRichEdit.TraceString(TEXT(绑定监听端口失败,请确认该端口没有被其它程序占用),TraceLevel_Warning); return; /监听套接字 if( !m_TCPSocketListen.Listen() ) m_TraceRichEdit.TraceString(TEXT(监听失败),TraceLevel_Warning); return; UINT uMaxConnect = GetDlgItemInt(IDC_MAX)

6、; /设置接口 m_TCPSocketListen.SetTCPSocketService(this); /更新界面 m_TraceRichEdit.TraceString(TEXT(服务器启动成功),TraceLevel_Normal); GetDlgItem(IDC_START)-EnableWindow(FALSE); GetDlgItem(IDC_STOP)-EnableWindow(TRUE);2、监听端口,收到连接请求,接受的代码:/先检验是否在服务器的最大连接限制内,若在,则获取当前客户的IP地址和端口等信息,插入链表中。/为什么要限制连接人数?因为TCP连接是相当占资源的,若不

7、限制连接人数,服务器的资源不够分配。void CSpeakerServerDlg:OnAccept() /承载能力 if ( m_TCPSocketItemMap.size() GetDlgItemInt(IDC_MAX) ) m_TraceRichEdit.TraceString(TEXT(服务器承载人数已满,已过滤其他连接),TraceLevel_Warning); return; /绑定套接字 CTCPSocketService *pTCPSocketConnect = new CTCPSocketService; try SOCKADDR_IN SocketAddr; int nBuf

8、ferSize = sizeof(SocketAddr); /连接 m_TCPSocketListen.Accept(*pTCPSocketConnect,(SOCKADDR *) &SocketAddr, &nBufferSize); if (pTCPSocketConnect-m_hSocket = INVALID_SOCKET) throw TEXT(无效的连接套接字); /获取客户端IP pTCPSocketConnect-m_dwClientAddr = SocketAddr.sin_addr.S_un.S_addr; pTCPSocketConnect-SetTCPSocketSe

9、rvice(this); /绑定数据 bool bActive = true; CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.begin(); for (;iter!= m_TCPSocketItemMap.end();iter+) if ( pTCPSocketConnect-m_hSocket = iter-first ) bActive = false; break; /插入客户数据 if ( bActive ) tagBindParameter *pBindParameter = new tagBindParameter; p

10、BindParameter-pTCPSocketService = pTCPSocketConnect; pBindParameter-dwUserID = 0; m_TCPSocketItemMap.insert(pair(pTCPSocketConnect-m_hSocket,pBindParameter); catch (.) if (pTCPSocketConnect-m_hSocket != INVALID_SOCKET) pTCPSocketConnect-Close(); 3、接收并检验数据的代码:void CSpeakerServerDlg:OnReceive(SOCKET h

11、Socket) BYTE cbDataBufferSOCKET_TCP_BUFFER; CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.find(hSocket); if ( iter = m_TCPSocketItemMap.end() ) return; /接收数据 iter-second-pTCPSocketService-Receive(cbDataBuffer,CountArray(cbDataBuffer) ); /解析数据 TCP_Command * pCommand=(TCP_Command *)cbDataBuffer

12、; /解释数据 WORD wPacketSize = pCommand-wPacketSize; WORD wDataSize = wPacketSize-sizeof(TCP_Command); /数据包效验 if ( wPacketSize SOCKET_TCP_BUFFER+sizeof TCP_Command ) m_TraceRichEdit.TraceString(TEXT(数据包太大,已拒绝),TraceLevel_Warning); return; /子消息处理事件 if( !OnEventTCPSocketRead(hSocket,pCommand-wMainCmdID,pC

13、ommand-wSubCmdID,pCommand+1,wDataSize) ) BYTE * pClientIP=(BYTE *)&iter-second-pTCPSocketService-m_dwClientAddr; m_TraceRichEdit.TraceString(TraceLevel_Warning,TEXT(收到伪数据包或未处理的数据包,wMainCmdID:%d,wSubCmdID:%d,来源IP:%d.%d.%d.%d),pCommand-wMainCmdID,pCommand-wSubCmdID,pClientIP0,pClientIP1,pClientIP2,pCl

14、ientIP3); return; 4、群发登录消息和用户发送的消息代码:/服务器收到客户的消息之后会将收到的消息发送给链表之中除了发送客户之外的所有客户。bool CSpeakerServerDlg:OnEventTCPSocketRead( SOCKET hSocket,WORD wMainCmdID, WORD wSubCmdID, VOID * pData, WORD wDataSize ) /获取绑定套接字 CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.find(hSocket); if ( iter = m_TCPSock

15、etItemMap.end() ) return false; CTCPSocketService *pTCPSocketService = iter-second-pTCPSocketService; switch ( wMainCmdID ) case MDM_GP_LOGON: if ( wSubCmdID = SUB_CS_LOGON ) /效验数据 ASSERT( wDataSize = sizeof CMD_CS_LOGON ); if ( wDataSize != sizeof CMD_CS_LOGON ) return false; /获取数据 CMD_CS_LOGON *pU

16、serLogon = (CMD_CS_LOGON*)pData; m_TraceRichEdit.TraceString(TraceLevel_Normal,TEXT(%s登陆服务器),pUserLogon-szUserName); tagUserData *pUserData = new tagUserData; /随机给用户分配一个UserID,UserID一般存储于数据库中,是一个独一无二的数字, /一般在数据库表中设为主键,是整个游戏或者软件识别用户的唯一依据,这里我们没有涉及到数据库,暂时随机取一个数值代替 /其次,我们应该通过数据库SQL语句查询或者存储过程等方法,或在数据库中做密

17、码的效验也好, /或在查询到用户的密码在服务器中进行判断也好,不管什么方法,此处一般需要进行用户密码的效验,这样才可以判定用户是否可以登陆了 pUserData-dwUserID = GetTickCount(); _sntprintf_s(pUserData-szUserName,CountArray(pUserData-szUserName),pUserLogon-szUserName); _sntprintf_s(pUserData-szPassWord,CountArray(pUserData-szPassWord),pUserLogon-szPassWord); /更新绑定数据 CT

18、CPSocketItemMap:iterator iter = m_TCPSocketItemMap.find(hSocket); if ( iter != m_TCPSocketItemMap.end() ) iter-second-dwUserID = pUserData-dwUserID; /群发登陆消息 SendUserItem(NULL,pUserData); /发送在线用户 CUserItemArray:iterator pUserItemSend = m_pUserManager-GetUserItemArray()-begin(); for (;pUserItemSend!=m

19、_pUserManager-GetUserItemArray()-end();pUserItemSend+ ) SendUserItem(pTCPSocketService,pUserItemSend-second); /插入数据 m_pUserManager-InsertUserItem(pUserData); return true; break; case MDM_GP_USER: if ( wSubCmdID = SUB_CS_USERT_CHAT ) /获取数据 CMD_CS_CHATMSG *pCHATMSG = (CMD_CS_CHATMSG*)pData; /这里其实需要做很多

20、的效验,如dwSendUserID的有效性,字符串是否为空等,这里就不做这些效验了 CMD_SC_CHATMSG _SC_CHATMSG; ZeroMemory(&_SC_CHATMSG,sizeof _SC_CHATMSG); /获取时间 GetLocalTime(&_SC_CHATMSG.SystemTime); _sntprintf_s(_SC_CHATMSG.szSendUserName,CountArray(_SC_CHATMSG.szSendUserName),m_pUserManager-GetUserName(iter-second-dwUserID); _sntprintf_

21、s(_SC_CHATMSG.szDescribe,CountArray(_SC_CHATMSG.szDescribe),pCHATMSG-szDescribe); SendDataBatch(MDM_GP_USER,SUB_CS_USERT_CHAT,&_SC_CHATMSG,sizeof _SC_CHATMSG); return true; break; return false;5、当服务器端有人退出登录时的代码:/客户端退出时,服务器端获取用户名并群发退出消息,再在链表中删除该用户的数据,清理他的Socketvoid CSpeakerServerDlg:OnClose(SOCKET hS

22、ocket) CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.find(hSocket); if ( iter = m_TCPSocketItemMap.end() ) return; /获取用户 m_TraceRichEdit.TraceString(TraceLevel_Normal,TEXT(%s退出了服务器),m_pUserManager-GetUserName(iter-second-dwUserID); /删除用户 CMD_DC_DELETE _DC_DELETE; ZeroMemory(&_DC_DELETE,sizeof

23、 _DC_DELETE); _sntprintf_s(_DC_DELETE.szUserName,CountArray(_DC_DELETE.szUserName),m_pUserManager-GetUserName(iter-second-dwUserID); /群发消息 SendDataBatch(MDM_GP_USER,SUB_SC_DELETE,&_DC_DELETE,sizeof _DC_DELETE); /销毁数据 m_pUserManager-RemoveUserItem(iter-second-dwUserID); iter-second-pTCPSocketService-

24、Close(); SafeDelete(iter-second-pTCPSocketService); SafeDelete(iter-second); m_TCPSocketItemMap.erase(iter);6、 关闭服务器连接代码:void CSpeakerServerDlg:OnBnClickedStop() /关闭监听套接字 m_TCPSocketListen.Close(); /关闭连接套接字 CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.begin(); for (;iter != m_TCPSocketItemMa

25、p.end(); +iter) iter-second-pTCPSocketService-Close(); SafeDelete(iter-second-pTCPSocketService); SafeDelete(iter-second); /更新界面 m_TraceRichEdit.TraceString(TEXT(服务器关闭成功),TraceLevel_Normal); GetDlgItem(IDC_START)-EnableWindow(TRUE); GetDlgItem(IDC_STOP)-EnableWindow(FALSE);7、退出服务器代码:void CSpeakerSer

26、verDlg:OnCancel() if ( m_TCPSocketListen.m_hSocket != INVALID_SOCKET ) if ( AfxMessageBox(TEXT(确定退出服务器吗?其它所有用户将失去连接),MB_YESNO|MB_ICONQUESTION) = IDYES ) CTCPSocketItemMap:iterator iter = m_TCPSocketItemMap.begin(); for (;iter != m_TCPSocketItemMap.end(); +iter) iter-second-pTCPSocketService-Close();

27、 SafeDelete(iter-second-pTCPSocketService); SafeDelete(iter-second); _super:OnCancel();客户端:1、客户端登录:/登陆消息LRESULT CSpeakerClientDlg:OnLogonMessage( WPARAM wParam,LPARAM lParam ) tagLogonInfo *pLogonInfo = (tagLogonInfo*)wParam; /关闭之前socket m_TCPScoketClient.Close(); /初始化套接字 if ( !m_TCPScoketClient.Cre

28、ate() ) SetTraceString(TEXT(套接字创建失败); SafeDelete(pLogonInfo); return FALSE; /创建连接 if( m_TCPScoketClient.Connect(pLogonInfo-szServerAddr,pLogonInfo-nPort) = FALSE ) int nErrorCode = m_TCPScoketClient.GetLastError(); if ( nErrorCode !=WSAEWOULDBLOCK ) SetTraceString(TEXT(连接服务器失败,错误码:%d),nErrorCode); S

29、afeDelete(pLogonInfo); return FALSE; /设置接口 m_TCPScoketClient.SetTCPSocketService(this); /构建数据 CMD_CS_LOGON UserLogon; ZeroMemory(&UserLogon,sizeof UserLogon); _sntprintf_s(UserLogon.szUserName,CountArray(UserLogon.szUserName),pLogonInfo-szUserName); _sntprintf_s(UserLogon.szPassWord,CountArray(UserLogon.szPassWord),pLogonInfo-szPassWord); /发送登陆请求 m_TCPScoketClient.SendData(MDM_GP_LOGON,SUB_CS_LOGON,&UserLogon,sizeof UserL

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

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