// ServerDlg.cpp : implementation file // #include "stdafx.h" #include "Server.h" #include "ServerDlg.h" #ifdef _DEBUG //判断是否定义了_DEBUG #define new DEBUG_NEW #undef THIS_FILE //取消THIS_FILE的定义 static char THIS_FILE[] = __FILE__; //THIS_FILE是一个char数组全局变量,字符串值为当前文件的全路径, //这样在Debug版本中当程序出错时出错处理代码可用这个变量告诉你是哪个文件中的代码有问题。 //__FILE__ 这个字符串就是当前在编译的文件的路径名 #endif ///////////////////////////////////////////////////////////////////////////// // CServerDlg dialog CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/) : CDialog(CServerDlg::IDD, pParent) { //{{AFX_DATA_INIT(CServerDlg) m_Ctx = _T(""); //}}AFX_DATA_INIT m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); //mfc 图标 } void CServerDlg::DoDataExchange(CDataExchange* pDX) //实现控件和变量之间的值传递,主要由DDX(动态数据交换)和 DDV(动态数据验证)宏实现 { //不要直接调用这个函数,而是通过UpdateData(TRUE/FALSE)实现控件与变量之间值的传递 CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CServerDlg) DDX_Control(pDX, IDC_PLAYER, m_List); DDX_Text(pDX, IDC_CTX, m_Ctx); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CServerDlg, CDialog) //{{AFX_MSG_MAP(CServerDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_BN_CLICKED(IDC_EXIT, OnExit) ON_MESSAGE(SOCKET_EVENT,OnSocket) ON_WM_CTLCOLOR() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CServerDlg message handlers BOOL CServerDlg::OnInitDialog() { CString msg; CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 //执行此操作 SetIcon(m_hIcon, TRUE); // Set big icon如果是TRUE,就是关闭了程序显示的图标 SetIcon(m_hIcon, FALSE); // Set small icon m_List.InsertColumn(0,"称谓",LVCFMT_LEFT,120); //第一列表头 m_List.InsertColumn(1,"IP",LVCFMT_LEFT,100); //第二列表头 m_List.InsertColumn(2,"消息数",LVCFMT_LEFT,60); //第三列表头 m_List.InsertColumn(3,"头像",LVCFMT_LEFT,60); //第四列表头 m_socket.AttachCWnd(this); //将Socket绑定到本窗 m_socket.Create(0x8123,SOCK_STREAM); //SOCK_STREAM表示TCP连接 m_socket.Listen(); //等待连接 m_brBack.DeleteObject(); m_bmBack.DeleteObject(); m_bmBack.LoadBitmap(IDB_BKSERVER); m_brBack.CreatePatternBrush(&m_bmBack); m_bExit.AutoLoad(IDC_EXIT,this); return TRUE; } void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam) { CDialog::OnSysCommand(nID, lParam); } void CServerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); int cxIcon = GetSystemMetrics(SM_CXICON); //得到图片的高高; int cyIcon = GetSystemMetrics(SM_CYICON); //得到图片的宽高; CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; //图片将要显示的位置; dc.DrawIcon(x, y, m_hIcon); //在指定的位置显示图片; } else { CDialog::OnPaint(); } } void CServerDlg::OnCancel() { CDialog::OnCancel(); } void CServerDlg::OnOK() { // CDialog::OnOK(); } void CServerDlg::OnExit() { CDialog::OnOK(); } //wParam对应与相应客户端通信的SOCKET指针,也有可能是主SOCKET,lParam对应事件类型 void CServerDlg::OnSocket(WPARAM wParam, LPARAM lParam) { CMySocket *sock = (CMySocket*)wParam; CMySocket *c; SOCKADDR_IN sockAddr; //SOCKADDR_IN是一个结构,表示IP地址、端口号等 int nSize = sizeof(sockAddr); BOOL res; switch(lParam) { case ACCEPT: //新的连接消息 c = new CMySocket; //创建一个新的SOCKET c->AttachCWnd(this); //将连接绑定到本窗体 res = sock->Accept(*c, (SOCKADDR *)&sockAddr,&nSize); //主SOCKET指派新创建的SOCKET与客户端通信 if(res == FALSE) MessageBox("Accept Error!"); break; case CLOSE: //连接关闭消息 ClosePlayer(sock); //关闭连接 break; case RETR: //收到数据消息 ParserPkt(sock); //解析消息 break; } } //解析收到的数据 void CServerDlg::ParserPkt(CMySocket *from) { char SendBuff[4096]; //发送缓冲 char ShowBuff[4096]; //显示缓冲 int len; //记录发送长度 int item; //列表序号 char pic[2]; //图像序号 CString ipaddr; //IP字符串 UINT port; //端口号 CMySocket *s1; //发送一般消息的Socket CMySocket *s; //发送用户进入信息的Socket char nbuf[100]; //临时缓冲区 //初始化各缓冲区 memset(SendBuff,0,4096); memset(ShowBuff,0,4096); memset(nbuf,0,100); len = from->Receive(SendBuff,4096); //读取数据 if(len < 1) //读取失败 return; if(SendBuff[0] == 0x11) //新用户加入 { from->GetPeerName(ipaddr,port); //取得与该套接字链接的对方的IP地址、端口号 from->m_Player = SendBuff + 2; //与SOCKET通信的用户的称谓 pic[0] = SendBuff[1] + 0x30; pic[1] = '\0'; //头像序号 m_csList.Lock(); item = m_List.InsertItem(0,SendBuff+2); //列表中插入一行,返回插入的行号 m_List.SetItemData(item,(DWORD)from); //保存该SOCKET指针到该行的附加数据域 m_List.SetItemText(item,1,ipaddr); //设置第2列,IP地址列 m_List.SetItemText(item,3,pic); //设置第3列,用户头像 m_csList.Unlock(); len = sprintf(ShowBuff ," %s 进入聊室。\r\n",from->m_Player); s1 = (CMySocket*)m_List.GetItemData(item); m_csList.Lock(); for(item = 0; item < m_List.GetItemCount(); item++) { s = (CMySocket*)m_List.GetItemData(item); //取附加数据(SOCKET指针) s->Send(SendBuff,len); //通知所有用户有新用户加入 Sleep(200); if(s != from) { //发送新用户加入消息 m_List.GetItemText(item,3,&pic[0],2); nbuf[0] = 0x31; nbuf[1] = pic[0]; m_List.GetItemText(item,0,nbuf+2,100); len = strlen(nbuf); s1->Send(nbuf,14); } else { //新用户消息加1 char tot[10]; sprintf(tot,"%u",from->m_Total); m_List.SetItemText(item,2,tot); //设置第2列,消息数列 } } m_csList.Unlock(); } else if(SendBuff[0] == 0x51) //私聊信息 { char pName[100],bName[100]; memset(pName,0,100); memset(bName,0,100); strcpy(pName,SendBuff +1); for(item = 0; item < m_List.GetItemCount(); item++) { m_List.GetItemText(item,0,bName,100); if(0 == strcmp(pName,bName)) { s = (CMySocket*)m_List.GetItemData(item); //取附加数据(SOCKET指针) s->Send(SendBuff + 99 ,len); } } memcpy(ShowBuff,SendBuff+99,3996); } else //公聊信息 { m_csList.Lock(); for(item = 0; item < m_List.GetItemCount(); item++) { s = (CMySocket*)m_List.GetItemData(item); //取附加数据(SOCKET指针) s->Send(SendBuff,len); if(s == from) { char tot[10]; sprintf(tot,"%u",from->m_Total); m_List.SetItemText(item,2,tot); //设置第2列,消息数列 } } m_csList.Unlock(); } Append(ShowBuff); } //处理用户退出事件 void CServerDlg::ClosePlayer(CMySocket *from) { int i,msg_len; char out_msg[200]; char nbuf[100]; nbuf[0] = 0x41; //用户退出的命令号 msg_len = sprintf(out_msg," %s 退出聊天室\r\n",from->m_Player) + 1; m_csList.Lock(); for(i = 0; i < m_List.GetItemCount(); i++) //删除退出用户的信息 { if(m_List.GetItemData(i) == (DWORD)from) { delete from; //删除套接字 m_List.GetItemText(i,0,nbuf + 1, 90); m_List.DeleteItem(i); //删除退出用户在列表中的信息 break; } } for(i = 0; i < m_List.GetItemCount(); i++) //将用户退出消息发送给各个用户 { CMySocket *s; s = (CMySocket*)m_List.GetItemData(i); s->Send(nbuf,90); //发送消息 } m_csList.Unlock(); Append(out_msg); } //追加消息体 void CServerDlg::Append(char *msg) { CEdit *pEd = (CEdit*)GetDlgItem(IDC_CTX); //读取消息框中所有 的消息 if(m_Ctx.GetLength() > 8196) //保存的消息过长 m_Ctx.Empty(); //清空消息 m_Ctx += msg; //追加新消息 UpdateData(FALSE); //显示 pEd->LineScroll(1000); } HBRUSH CServerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if(nCtlColor == CTLCOLOR_DLG) return m_brBack; return hbr; }