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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

本文(计算机网络课设基于TCP协议编程的网络聊天室.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至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) 和客 户端 (Speak

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

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

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

6、return;UINT uMaxConnect = GetDlgItemInt(IDC_MAX);/ 设置接口m_TCPSocketListen.SetTCPSocketService(this);/ 更新界面m_TraceRichEdit.TraceString(TEXT( 服务器启动成功 ),TraceLevel_Normal);GetDlgItem(IDC_START)-EnableWindow(FALSE);GetDlgItem(IDC_STOP)-EnableWindow(TRUE);2、监听端口,收到连接请求,接受的代码:/ 先检验是否在服务器的最大连接限制内, 若在,则获取当前客

7、户的 IP 地址和端口等信息, 插入链表中。/为什么要限制连接人数?因为 TCP连接是相当占资源的, 若不限制连接人数,服务器的资源不够分配。void CSpeakerServerDlg:OnAccept()/ 承载能力if ( m_TCPSocketItemMap.size() GetDlgItemInt(IDC_MAX) )m_TraceRichEdit.TraceString(TEXT( 服务器承载人数已满,已过滤其他连接 ),TraceLevel_Warning);return;/ 绑定套接字CTCPSocketService *pTCPSocketConnect = new CTCP

8、SocketService;trySOCKADDR_INSocketAddr;int nBufferSize = sizeof(SocketAddr);/ 连接m_TCPSocketListen.Accept(*pTCPSocketConnect,(SOCKADDR *) &SocketAddr, &nBufferSize);if (pTCPSocketConnect-m_hSocket = INVALID_SOCKET) throw TEXT( 无效的连接套接字 );/ 获取客户端 IPpTCPSocketConnect-m_dwClientAddr = SocketAddr.sin_add

9、r.S_un.S_addr; pTCPSocketConnect-SetTCPSocketService(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 *p

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

11、peakerServerDlg:OnReceive(SOCKET hSocket)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 * pComman

12、d=(TCP_Command *)cbDataBuffer;/ 解释数据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(hSock

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

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

15、t);if ( iter = m_TCPSocketItemMap.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;/ 获取数

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

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

18、on -szPassWord);/ 更新绑定数据CTCPSocketItemMap: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();f

19、or (;pUserItemSend!=m_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);

21、_sntprintf_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:OnC

22、lose(SOCKET hSocket)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_DEL

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

24、ervice-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_TCPSocketItemM

25、ap.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 CSpeakerServer

26、Dlg: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();Safe

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

28、败 );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);SafeDelete(pLogonInfo);return FALSE;/

29、 设置接口/ 构建数据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_LO

30、GON,SUB_CS_LOGON,&UserLogon,sizeof UserLogon);/ 设置界面SetTraceString(TEXT( 连接服务器成功 );m_LogonDlg.PostMessage(WM_CLOSE);/ 清理数据SafeDelete(pLogonInfo);return TRUE;2、客户端发送数据代码:void CSpeakerClientDlg:OnBnClickedSend()/ 设置数据CMD_CS_CHATMSG _UserChat_Msg;ZeroMemory(&_UserChat_Msg,sizeof _UserChat_Msg);GetDlgItemText(IDC_EDITCHAT,_UserChat_Msg.szDescribe,CountArray(_UserChat_Msg.s zDescribe);/ 效验

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

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