1、服务器采用WINSOCK I/O模型中的任一种,支持多个客户同时在线聊天。客户端程序和服务器程序通过网络交换聊天字符串容,服务器窗口的列表框中显示当前在线用户,支持客户端之间的私聊(可以通过服务器中转,或考虑UDP打洞直接建立端端连接)。二、设计原理服务器端通过socket()系统调用创建一个Socket数组后(即设定了接受连接客户的最大数目),与指定的本地端口绑定bind(),就可以在端口进行侦听listen()。如果有客户端连接请求,则在数组中选择一个空Socket,将客户端地址赋给这个Socket。然后登录成功的客户就可以在服务器上聊天了。客户端程序相对简单,只需要建立一个Socket与
2、服务器端连接,成功后通过这个Socket来发送和接收数据就可以了。socket聊天室基本原理是,抛开CGI(公共网关接口)和www服务器,根据html规,接收到浏览器的请求以后,模仿www服务器的响应,将聊天容发回浏览器。在浏览器看来就像浏览一个巨大的页面一样始终处于页面联接状态, 这就是一个专门的聊天服务器,一个简化了的www服务器。三、设计过程1、程序设计流程与源代码(1)流程图 (2)源代码I服务器:/ ServerDlg.cpp : implementation file/#include stdafx.hServer.hServerDlg.h#ifdef _DEBUG#define
3、new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE = _FILE_;#endif/ CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialogpublic: CAboutDlg();protected: DECLARE_MESSAGE_MAP();CAboutDlg:CAboutDlg() : CDialog(CAboutDlg:IDD)void CAboutDlg:DoDataExchange(CDataExchange* pDX) CDialog:DoDataEx
4、change(pDX);BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)END_MESSAGE_MAP()/ CServerDlg dialogCServerDlg:CServerDlg(CWnd* pParent /*=NULL*/) : CDialog(CServerDlg:IDD, pParent) m_hIcon = AfxGetApp()-LoadIcon(IDI_ICONAPP);void CServerDlg: DDX_Control(pDX, IDC_LIST_USER, m_lbUser); DDX_Text(pDX, IDC_EDIT_DISPLA
5、Y, m_strDisplay);BEGIN_MESSAGE_MAP(CServerDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BN_START, OnBnStart) ON_BN_CLICKED(IDC_BN_CLOSE, OnBnClose) ON_MESSAGE(WM_RECEIVE, OnReceive) ON_MESSAGE(WM_CLIENTCLOSE, OnClientClose) ON_MESSAGE(WM_ACCEPT, OnAccept) ON_
6、WM_DESTROY()/ CServerDlg message handlersBOOL CServerDlg:OnInitDialog()OnInitDialog(); ASSERT(IDM_ABOUTBOX & 0xFFF0) = IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX AppendMenu(MF_SEPARATOR);AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); SetIcon(m_hIcon, TRUE); / Set big icon SetIcon(m_hIcon, FALSE); / Set
7、small icon m_iNetPort = 3127; m_Server.Initialize(this); m_bServer = FALSE; GetDlgItem(IDC_BN_CLOSE)-EnableWindow(FALSE); return TRUE; / return TRUE unless you set the focus to a controlOnSysCommand(UINT nID, LPARAM lParam) if (nID & 0xFFF0) = IDM_ABOUTBOX) CAboutDlg dlgAbout; dlgAbout.DoModal(); el
8、se CDialog:OnSysCommand(nID, lParam);OnPaint() if (IsIconic() CPaintDC dc(this); / device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (r
9、ect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; dc.DrawIcon(x, y, m_hIcon);OnPaint();HCURSOR CServerDlg:OnQueryDragIcon() return (HCURSOR) m_hIcon;OnBnStart() / 创建套接字 m_Server.Create(m_iNetPort); / 开始监听 m_Server.Listen(); / 显示 CString strInfo; strInfo.LoadString(IDS_CREATE_S
10、ERVER); ShowInDisplay(strInfo); m_bServer = TRUE; GetDlgItem(IDC_BN_START)-EnableWindow(TRUE);OnBnClose() CloseServer();OnAccept() / 创建新客户 CMySocket *pNewClient = new CMySocket; pNewClient-Initialize(this); m_Server.Accept(*pNewClient); / 放入链表中 m_lsClient.AddTail(pNewClient);OnClientClose(WPARAM wPa
11、ram, LPARAM lParam) CMySocket *p_delClient = (CMySocket*)wParam; / 关闭该用户 p_delClient-ShutDown(); char bufferBUFFERSIZE; while(p_delClient-Receive(buffer, BUFFERSIZE)0);Close(); / 在用户链表中删除该用户 POSITION psCur, psList = m_lsClient.GetHeadPosition(); CMySocket *p_curClient; while(psList!=NULL) psCur = ps
12、List; p_curClient = (CMySocket *)m_lsClient.GetNext(psList); if(p_delClient=p_curClient) m_lsClient.RemoveAt(psCur); break; / 发送信息告诉其他用户该客户退出 CString strMsg; strMsg.LoadString(IDS_CLIENT_CLOSE); NETMESSAGE netMessage(PTC_CLIENT_QUIT, p_delClient-GetName(), _T(), p_delClient-GetName() + strMsg); Send
13、ToAllClient(netMessage); / 界面上清理该用户信息 m_lbUser.DeleteString(m_lbUser.FindString(-1, p_delClient-GetName(); ShowInDisplay(p_delClient- / 删除该用户 delete p_delClient;OnReceive(WPARAM wParam, LPARAM lParam) CMySocket *p_curClient = (CMySocket*)wParam; NETMESSAGE netMessage; p_curClient-Receive(char *)&net
14、Message, sizeof(netMessage); switch(netMessage.type) case PTC_NEW: / 新客户加入 NewClientAdd(p_curClient, &netMessage); case PTC_SAY: / 普通聊天 ShowMessage(netMessage); / 把加工过的信息发送给其他用户CloseServer() if(!m_bServer) return; / 向所有客户发送服务端关闭的信息 strInfo.LoadString(IDS_CLOSESERVER); NETMESSAGE netMessage(PTC_SYSTE
15、M, _T(), _T(), strInfo); / 服务端界面显示关闭信息 / 关闭服务端 m_Server.Close(); / 关闭客户端 CMySocket *m_pClient; POSITION psList = m_lsClient.GetHeadPosition(); m_pClient = (CMySocket *)m_lsClient.GetNext(psList); m_pClient- while(m_pClient- delete m_pClient; m_lsClient.RemoveAll();/ 向所有户发出信息SendToAllClient(const NET
16、MESSAGE &netMessage)SendMsg(netMessage);ShowInDisplay(CString str) m_strDisplay += str + rn; UpdateData(false);OnDestroy() OnDestroy(); / TODO: Add your message handler code here/ 新用户加入 NewClientAdd(CMySocket *p_client, NETMESSAGE *netMessage) / 存入用户名字 p_client-SetName(netMessage-form); / 在列表框中显示该用户
17、 m_lbUser.AddString(p_client-GetName(); / 发送用户列表给该客户 NETMESSAGE netMsg(PTC_USER_LIST, _T(); int iListLen = m_lbUser.GetCount(); for(int index=m_lbUser.GetTopIndex(); indexSendMsg(netMsg); / 加工信息 strMsg.LoadString(IDS_NEW_CLIENT); strMsg = p_client-GetName() + strMsg; strcpy(netMessage-data, (LPCTSTR
18、)strMsg); / 显示该用户进入 ShowInDisplay(strMsg);/ 显示普通消息ShowMessage(NETMESSAGE netMessage) CString strTo = netMessage.to; if(strTo=_T() strTo = 所有人 CString strForm = netMessage.form; CString strMsg = netMessage.data; CString strOut = strForm + 对 + strTo + 说: + strMsg; ShowInDisplay(strOut);II客户端:/ ClientD
19、lg.cpp :Client.hClientDlg.hstatic char THIS_FILE = _FILE_; enum IDD = IDD_ABOUTBOX ; protected: virtual void DoDataExchange(CDataExchange* pDX); / DDX/DDV support/ CClientDlg dialogCClientDlg:CClientDlg(CWnd* pParent /*=NULL*/) CDialog(CClientDlg: m_strDisplay = _T(); m_strSend = _T( m_bWhispering = FALSE;LoadIcon(IDR_MAINFRAME);void CClientDlg: DDX_Control(pDX, IDC_LIST_USER, m_lbUser); DDX_Text(pDX, IDC_EDIT_DIAPLAY, m_strDisplay); DDX_Text(pDX, IDC_EDIT_SEND, m_strSend); DDX_Check(pDX, IDC_CHECK_WHISPERING, m
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1