1 / 34

教学内容

教学内容. 第 9 章 网络编程. 聊天室程序 演示 CSocket 程序设计基础 基于 Csocket 的网络编程 聊天室客户端应用程序 的开发 聊天室服务器端应用程序 扩充练习. 返 回. §9.1 公众聊天室程序. 服务器端程序 ( 演示程序 ) 客户端程序 ( 演示程序 ). 返 回. §9.2 CSocket 程序设计基础. 计算机名、 IP 地址和端口 WinSock 的工作原理 服务器端的编程步骤 客户端编程步骤. 要点提示:. 返回目录. 计算机名、 IP 地址和端口. 1. IP 地址

lupita
Download Presentation

教学内容

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 教学内容 • 第9章 网络编程 • 聊天室程序演示 • CSocket程序设计基础 • 基于Csocket的网络编程 • 聊天室客户端应用程序的开发 • 聊天室服务器端应用程序 • 扩充练习 返 回

  2. §9.1 公众聊天室程序 • 服务器端程序 (演示程序) • 客户端程序 (演示程序) 返 回

  3. §9.2 CSocket程序设计基础 • 计算机名、IP地址和端口 • WinSock的工作原理 • 服务器端的编程步骤 • 客户端编程步骤 要点提示: 返回目录

  4. 计算机名、IP地址和端口 1.IP地址 IP地址是一个32位的数字,用于唯一标识位于网络中的计算机。IP地址由两部分组成:网络标识和主机标识。IP地址的格式有两类:二进制和十进制格式。32位二进制的IP地址以8为单位进行分隔,换算成十进制,每个十进制数之间用“.”隔开。 例如: 10100010,1110010,1011111,10000001转化为十进制的IP地址是: 162.114.95.129 为了便于对IP地址进行管理,将IP地址分为5类,如图9-3所示。 2.计算机名 避免输入计算机的IP地址带来的麻烦,我们可以通过计算机名来代替IP地址。

  5. 计算机名、IP地址和端口(续) 3.端口 在利用计算机网络进行通讯时,除利用IP地址找到指定的计算机外,还要通过端口(Port)来标识进行通讯的进程,TCP/UDP协议为每个端口都分配一个端口号,当进程通过系统调用,同一个或多个端口建立联系后,就可已通过这些端口进行数据传输了。 TCP/IP端口号有16位,因此可以有216个端口。在这216个端口中,有一些是保留端口,由权威机构分配,用于特殊目的。例如,端口80被用作超文本协议和WWW服务。保留端口外的端口为自由端口,以本地方式进行分配。 返回目录

  6. 利用WinSock进行有连接的通信 使用TCP传输协议,可以与指定IP地址的主机建立连接,采用流的方式进行数据传输,优点是保证网络数据传输的可靠性,对没有到达的数据进行重传,通过效验确定数据是否正确。工作方式如图9-4所示。 返回目录

  7. 利用WinSock进行无连接的通信 使用UDP数据报传输协议,可以与指定IP地址的主机发送数据,也可以从指定IP地址的主机接收数据,发送和接收方处于相同的地位,没有主次之分如图9-5所示。 返回目录

  8. §9.3基于CSocket的网络编程 服务器端的编程步骤: • 从CSocket类派生一个新类 • 创建一个CSocket派生类对象 • 调用CSocket::Create()创建一个套接口,并指定端口 • 调用CSocket::Listen()函数侦听端口 • 在CSocket派生类中添加虚函数OnAccept()调用CSocket::Accept()接受客户的连接请求 • CSocket派生类中添加虚函数OnReceive()调用CSocket::Receive()接受数据 • 调用Close()函数关闭为各个客户分配的读套接口。 返回目录

  9. 基于CSocket的网络编程(续) 客户端的编程步骤: • 创建CSocket类的派生类对象,用于连接和读写 • 调用CSocket::Create( ) 创建一个套接口 • 调用CSocket::Connect( )连接服务器的指定端口 • 调用CSocket::Send( ) 发送数据 • 在CSocket::OnReceive( )函数中进行读写操作 • 结束通讯时,调用CSocket::Close( ) 关闭套接口 返回目录

  10. §9.4 聊天室客户端应用程序 要点提示: • 9.4.1 创建工程MyWc(设置“Windows Sockets”支持) • 9.4.2 可视化设计用户界面(参考表9.2) • 9.4.3 创建一个新类CWCSock,用于与服务器通信 • 9.4.4 接受服务器发来的数据 • 9.4.6 建立与服务器的连接 • 9.4.6 向服务器发送数据 • 9.4.7 建立CMyWcDlg类与CWCSock类的关联 • 9.4.8 处理自定义消息 • 9.4.9 处理控件的状态 返回目录

  11. 返回目录 创建与服务器的通信类CWSock 1. 选择“Insert”菜单的“New Class”菜单项,在New Class对话框中,Bass class列表框中选取CSocket作为基类 2. 单击“OK”按钮,VC++就为MyWc工程创建了一个新类CWCSocket,相应地为工程创建了两个文件WCSocket.h和WCSocket.cpp

  12. 建立与服务器的连接 void CMyWcDlg::OnConnect() { UpdateData(true); //更新关联变量,如服务器名、端口号 if(!sockClient.Create()) //1创建套接口 { AfxMessageBox("Create WC socket failed"); PostQuitMessage(0); } if(!sockClient.Connect(m_server_name,m_nPort))//2连接服务器 { MessageBox("连接失败!"); return; } m_Dat.m_bOnline=true;//标记连接成功 } 返回目录

  13. 向服务器发送数据 void CMyWcDlg::OnSend() { UpdateData(true); //更新关联变量,如要发送的信息   m_Dat.m_bOnline=true; memset(m_Dat.m_dbData,0,255); memcpy(m_Dat.m_dbData,m_send_info,m_send_info.GetLength());   strcpy(m_Dat.m_strName,m_client_name); int iSent = sockClient.Send(&m_Dat,sizeof(m_Dat)); //发送的信息 //如果发送成功,将其发送的信息添加并显示在列表编辑框 if(iSent != SOCKET_ERROR) { m_ctlSent.AddString(m_send_info); UpdateData(false); // 显示更新 } } 返回目录

  14. 接受服务器发来的数据 1. 添加虚拟函数 用MFC ClassWizard在CWCSock类中添加虚函数OnReceive() 2. 读取服务器传来的数据,通知主窗口进行处理 void CWCSock::OnReceive(int nErrorCode) { if(Receive(&m_Dat,sizeof(m_Dat))==sizeof(m_Dat)) ::PostMessage(::AfxGetApp()->m_pMainWnd->m_hWnd, RE_RECEIVED, (WPARAM)&m_Dat,0); CSocket::OnReceive(nErrorCode); } 返回目录

  15. 建立CMyWcDlg类与CWCSock类的关联 1. 在CMyWcDlg类中添加CWCSock类的对象,使它们相互关联。方法是在MyWcDlg.h文件中,在CMyWcDlg类定义前面添加如下语句: #include "WCSock.h" 2. 在CMyWcDlg类定义中添加如下语句: CWCSock sockClient; 返回目录

  16. 处理自定义消息 1. 在WCSock.h中,定义自定义消息,以使CWCSock能够同应用程序主窗口通信。 #define RE_RECEIVED WM_USER+1 2.在CMyWcDlg.cpp文件中,添加消息映射宏,响应CWCSock类对象发送过来的自定义消息RE_RECEIVED BEGIN_MESSAGE_MAP(CMyWcDlg, CDialog) //{{AFX_MSG_MAP(CMyWcDlg) …… ON_BN_CLICKED(IDC_SEND, OnSend) ON_MESSAGE(RE_RECEIVED,OnReceive); //}}AFX_MSG_MAP END_MESSAGE_MAP() 返回目录

  17. 处理自定义消息(续一) 3.在CMyWcDlg类添加自定义函数OnMyReceive class CMyWcDlg : public CDialog { public: CMyWcDlg(CWnd* pParent = NULL); CWCSock sockClient; ……  //自定义函数说明 LRESULT OnMyReceive(WPARAM wparam,LPARAM lParam); …… } 返回目录

  18. 处理自定义消息(续二) 4. 在CMyWcDlg类的实现文件中添加函数体 LRESULT CMyWcDlg::OnMyReceive(WPARAM wparam,LPARAM lParam) { _DATA *dat; dat = new _DATA; memcpy(dat,(_DATA *)wparam,sizeof(_DATA)); CString str = dat->m_strName; str += ": "; str += dat->m_dbData; m_ctlRecvd.AddString(str);//将信息添加并显示在列表框中 UpdateData(false); //显示列表编辑框内容 delete dat; return 1; } 返回目录

  19. 处理控件的状态 1. 在OnClose()和OnInitDialog()函数中 GetDlgItem(IDC_CONNECT)->EnableWindow(true); GetDlgItem(IDC_SEND)->EnableWindow(false); GetDlgItem(IDC_CLOSE)->EnableWindow(false); GetDlgItem(IDC_SERVER_PORT)->EnableWindow(true); GetDlgItem(IDC_CLIENT_NAME)->EnableWindow(true); GetDlgItem(IDC_SERVER_NAME)->EnableWindow(true); 返回目录

  20. 处理控件的状态(续) 2. 在OnConnect()函数中 GetDlgItem(IDC_CONNECT)->EnableWindow(false); GetDlgItem(IDC_SEND)->EnableWindow(true); GetDlgItem(IDC_CLOSE)->EnableWindow(true); GetDlgItem(IDC_SERVER_PORT)->EnableWindow(false); GetDlgItem(IDC_CLIENT_NAME)->EnableWindow(false); GetDlgItem(IDC_SERVER_NAME)->EnableWindow(false); 返回目录

  21. §9.5 聊天室服务器端应用程序 要点提示: • 9.5.1 创建工程 • 9.5.2 设计用户界面 • 9.5.3 创建侦听类CLSock • 9.5.4 增加读/写类CRWSock • 9.5.8 处理接受客户的信息 • 9.5.9 处理客户的连接请求 • 9.5.10 启动、关闭服务器 • 9.5.11 控件的状态更新 返回目录

  22. 创建侦听类CLSock (1) 选择“Insert”菜单的“New Class”菜单项,弹出New Class对话框 (2) 在New Class对话框中,Bass class下拉式列表框中选取CSocket作为CLSocket的基类。如下图所示。 (3) 单击“OK”按钮,VC++就为MyWs工程创建了一个新类CLSocket,相应地为工程创建了两个文件LSocket.h和LSocket.cpp 返回目录

  23. 返回目录 增加一个读写类CRWSock 创建CSocket类的派生类CRWSock,与侦听类CLSock位于相同的LSock.h,LSock.cpp文件中。 ① 选择“Insert”菜单的“New Class”菜单项,弹出New Class对话框 ② 在New Class对话框中,Bass class下拉式列表框中选取CSocket作为CRWSock的基类 ③ 单击“Change…”按钮,弹出“Change Files”对话框。将Header file编辑框修改为LSock.h,Implementation file编辑框框修改为LSock.cpp,如图所示。

  24. 处理接受客户的信息 1.在CRWSock类中,添加虚拟函数OnReceive() 2. 在虚拟函数OnReceive()中接收客户传来的数据,首先添加到列表编辑框并显示,然后再分两种情况处理: 当收到客户离线信息时,就从套接口链表中删除该结点; 否则,将收到的信息发送给在线的客户。 void CRWSock::OnReceive(int nErrorCode) { m_p->ReadMessage(this); CSocket::OnReceive(nErrorCode); } 返回目录 转下页

  25. 返 回 读取客户的信息(续一) void CMyWsDlg::ReadMessage(CRWSock* sock) { int len = sock->Receive(&m_Dat,sizeof(m_Dat)); _DATA *dat = &m_Dat; CString str = "收到客户机(";str += dat->m_strName; str += “)的信息:”; str += dat->m_dbData; m_ctlRecvd.AddString(str); if(m_Dat.m_bOnline)SendMessage(sock,&m_Dat); else { sock->Close(); POSITION pos = m_list.Find(sock); m_list.RemoveAt(pos);delete sock; } }

  26. 向在线的客户发送信息(续二) void CMyWsDlg::SendMessage(CRWSock* socket,_DATA *buf) { POSITION pos = m_list.GetHeadPosition( ); while ( pos != NULL) { CRWSock *client =(CRWSock*)m_list.GetNext(pos); if(client == socket)continue; client->Send(buf,sizeof(m_Dat)); } } 返 回

  27. 处理客户的连接请求 返回目录 1.在CmyWsDlg类中,添加一个CPtrList类的对象,用于管理各个客户的套接口 CPtrList m_list; 2.在CLSock类中添加虚拟函数OnAccept(),用于处理客户的连接请求 void CLSock::OnAccept(int nErrorCode) { ASSERT(m_p); m_p->AcceptClient(); CSocket::OnAccept(nErrorCode); } 转下页

  28. 处理客户的连接请求(续) 创建套接口,添加到链表中 void CMyWsDlg::AcceptClient() { m_clientSocket = new CRWSock(this); if(!m_listenSocket->Accept(*m_clientSocket)) { AfxMessageBox("请求连接失败"); delete m_clientSocket; m_clientSocket=NULL; return; } m_list.AddTail(m_clientSocket); } 返 回

  29. 启动服务器 返回目录 void CMyWsDlg::OnStart() { UpdateData(true); //①创建套接口 m_listenSocket = new CLSock(this); if(!m_listenSocket->Create(m_server_port)) {delete m_listenSocket; m_listenSocket=NULL;return;} //②进入侦听状态 if(!m_listenSocket->Listen()) { delete m_listenSocket;m_listenSocket=NULL;return;} }

  30. 关闭服务器 返 回 void CMyWsDlg::OnClose() { POSITION pos = m_list.GetHeadPosition(); while( pos != NULL )//①从套接口链表中删除所有结点 { CRWSock* client=(CRWSock*)m_list.GetNext(pos); delete client; } if(m_listenSocket != NULL)//②关闭读套接口 { m_listenSocket->Close(); delete m_listenSocket; } }

  31. 控件的状态更新 返回目录 1.在OnStart()函数中末添加如下控件的状态更新语句: GetDlgItem(IDC_START)->EnableWindow(false); GetDlgItem(IDC_CLOSE)->EnableWindow(true); GetDlgItem(IDC_SERVER_PORT)->EnableWindow(false); 2.在OnClose()和OnInitDialog()函数中末添加如下控件的状态更新语句: GetDlgItem(IDC_START)->EnableWindow(true); GetDlgItem(IDC_CLOSE)->EnableWindow(false); GetDlgItem(IDC_SERVER_PORT)->EnableWindow(true);

  32. 扩充练习 1.修改聊天室程序,使客户断聊天室信息中,也包含自己发送的文字信息; 2.修改聊天室程序,在客户端,增加客户登入界面。 3.完善聊天室程序,添加客户可选的聊天对象,即私人聊天活多人聊天。 请批评指导,谢谢! 返回目录

More Related