基于WSAAsyncSelect模型实现的聊天室图形客户端

来源:互联网 发布:nginx ab压力测试 编辑:程序博客网 时间:2024/06/05 06:10

 

 

对应的Linux服务器为:http://blog.csdn.net/microtong/archive/2009/12/12/4989902.aspx

 

 

头文件ClientDlg.h

[cpp] view plaincopy
  1. // ClientDlg.h : 头文件  
  2. //  
  3. #pragma once  
  4. #include "afxcmn.h"  
  5. #include "afxwin.h"  
  6. #define WM_NETWORK WM_USER+100  
  7. // CClientDlg 对话框  
  8. class CClientDlg : public CDialog  
  9. {  
  10. // 构造  
  11. public:  
  12.     CClientDlg(CWnd* pParent = NULL);   // 标准构造函数  
  13. // 对话框数据  
  14.     enum { IDD = IDD_CLIENT_DIALOG };  
  15.     protected:  
  16.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  17.   
  18. // 实现  
  19. protected:  
  20.     HICON m_hIcon;  
  21.     // 生成的消息映射函数  
  22.     virtual BOOL OnInitDialog();  
  23.     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);  
  24.     afx_msg void OnPaint();  
  25.     afx_msg HCURSOR OnQueryDragIcon();  
  26.     DECLARE_MESSAGE_MAP()  
  27. public:  
  28.     CIPAddressCtrl m_ip;  
  29.     int m_port;  
  30.     CEdit m_allmsg;  
  31.     CString m_nickname;  
  32.     CString m_message;  
  33.     afx_msg void OnBnClickedConnect();  
  34.     // 服务器套接字  
  35.     SOCKET sock;  
  36.     struct sockaddr_in serverAddr;  
  37.     CString msg;  
  38.     LRESULT OnNetwork(WPARAM wParam, LPARAM lParam);  
  39.     void OnConnect(SOCKET s);  
  40.     void OnRead(SOCKET s);  
  41.     void OnCloseSocket(SOCKET s);  
  42.     afx_msg void OnBnClickedSend();  
  43.     afx_msg void OnBnClickedDisconnect();  
  44.     afx_msg void OnClose();  
  45.     afx_msg void OnBnClickedQuit();  
  46.     afx_msg void OnBnClickedChangeName();  
  47. };  

 

对话框源文件 ClientDlg.cpp

 

[cpp] view plaincopy
  1. // ClientDlg.cpp : 实现文件  
  2. //  
  3. #include "stdafx.h"  
  4. #include "Client.h"  
  5. #include "ClientDlg.h"  
  6. #ifdef _DEBUG  
  7. #define new DEBUG_NEW  
  8. #endif  
  9.   
  10. // 用于应用程序“关于”菜单项的 CAboutDlg 对话框  
  11. class CAboutDlg : public CDialog  
  12. {  
  13. public:  
  14.     CAboutDlg();  
  15. // 对话框数据  
  16.     enum { IDD = IDD_ABOUTBOX };  
  17.     protected:  
  18.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  19. // 实现  
  20. protected:  
  21.     DECLARE_MESSAGE_MAP()  
  22. };  
  23. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)  
  24. {  
  25. }  
  26. void CAboutDlg::DoDataExchange(CDataExchange* pDX)  
  27. {  
  28.     CDialog::DoDataExchange(pDX);  
  29. }  
  30. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)  
  31. END_MESSAGE_MAP()  
  32.   
  33. // CClientDlg 对话框  
  34.   
  35.   
  36. CClientDlg::CClientDlg(CWnd* pParent /*=NULL*/)  
  37.     : CDialog(CClientDlg::IDD, pParent)  
  38.     , m_port(8000)  
  39.     , m_nickname(_T("microtong"))  
  40.     , m_message(_T("hello"))  
  41. {  
  42.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
  43. }  
  44. void CClientDlg::DoDataExchange(CDataExchange* pDX)  
  45. {  
  46.     CDialog::DoDataExchange(pDX);  
  47.     DDX_Control(pDX, IDC_IP, m_ip);  
  48.     DDX_Text(pDX, IDC_PORT, m_port);  
  49.     DDX_Control(pDX, IDC_ALLMESSAGE, m_allmsg);  
  50.     DDX_Text(pDX, IDC_NICKNAME, m_nickname);  
  51.     DDV_MaxChars(pDX, m_nickname, 30);  
  52.     DDX_Text(pDX, IDC_MESSAGE, m_message);  
  53.     DDV_MaxChars(pDX, m_message, 1024);  
  54. }  
  55. BEGIN_MESSAGE_MAP(CClientDlg, CDialog)  
  56.     ON_WM_SYSCOMMAND()  
  57.     ON_WM_PAINT()  
  58.     ON_WM_QUERYDRAGICON()  
  59.     //}}AFX_MSG_MAP  
  60.     ON_BN_CLICKED(IDC_CONNECT, &CClientDlg::OnBnClickedConnect)  
  61.     ON_BN_CLICKED(IDC_SEND, &CClientDlg::OnBnClickedSend)  
  62.     ON_BN_CLICKED(IDC_DISCONNECT, &CClientDlg::OnBnClickedDisconnect)  
  63.     ON_WM_CLOSE()  
  64.     ON_BN_CLICKED(IDC_QUIT, &CClientDlg::OnBnClickedQuit)  
  65.     ON_BN_CLICKED(IDC_CHANGENAME, &CClientDlg::OnBnClickedChangeName)  
  66.     ON_MESSAGE(WM_NETWORK,&CClientDlg::OnNetwork)  
  67. END_MESSAGE_MAP()  
  68.   
  69. // CClientDlg 消息处理程序  
  70. BOOL CClientDlg::OnInitDialog()  
  71. {  
  72.     CDialog::OnInitDialog();  
  73.     // 将“关于...”菜单项添加到系统菜单中。  
  74.     // IDM_ABOUTBOX 必须在系统命令范围内。  
  75.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  
  76.     ASSERT(IDM_ABOUTBOX < 0xF000);  
  77.     CMenu* pSysMenu = GetSystemMenu(FALSE);  
  78.     if (pSysMenu != NULL)  
  79.     {  
  80.         CString strAboutMenu;  
  81.         strAboutMenu.LoadString(IDS_ABOUTBOX);  
  82.         if (!strAboutMenu.IsEmpty())  
  83.         {  
  84.             pSysMenu->AppendMenu(MF_SEPARATOR);  
  85.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
  86.         }  
  87.     }  
  88.     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动  
  89.     //  执行此操作  
  90.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  91.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  92.     // TODO: 在此添加额外的初始化代码  
  93.     //为测试方便IP地址初始化为本机IP地址  
  94.     m_ip.SetAddress(127,0,0,1);  
  95.     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE  
  96. }  
  97. void CClientDlg::OnSysCommand(UINT nID, LPARAM lParam)  
  98. {  
  99.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)  
  100.     {  
  101.         CAboutDlg dlgAbout;  
  102.         dlgAbout.DoModal();  
  103.     }  
  104.     else  
  105.     {  
  106.         CDialog::OnSysCommand(nID, lParam);  
  107.     }  
  108. }  
  109. // 如果向对话框添加最小化按钮,则需要下面的代码  
  110. //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,  
  111. //  这将由框架自动完成。  
  112. void CClientDlg::OnPaint()  
  113. {  
  114.     if (IsIconic())  
  115.     {  
  116.         CPaintDC dc(this); // 用于绘制的设备上下文  
  117.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  118.         // 使图标在工作矩形中居中  
  119.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  120.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  121.         CRect rect;  
  122.         GetClientRect(&rect);  
  123.         int x = (rect.Width() - cxIcon + 1) / 2;  
  124.         int y = (rect.Height() - cyIcon + 1) / 2;  
  125.         // 绘制图标  
  126.         dc.DrawIcon(x, y, m_hIcon);  
  127.     }  
  128.     else  
  129.     {  
  130.         CDialog::OnPaint();  
  131.     }  
  132. }  
  133. //当用户拖动最小化窗口时系统调用此函数取得光标显示。  
  134. //  
  135. HCURSOR CClientDlg::OnQueryDragIcon()  
  136. {  
  137.     return static_cast<HCURSOR>(m_hIcon);  
  138. }  
  139.   
  140. void CClientDlg::OnBnClickedConnect()  
  141. {  
  142.     UpdateData(TRUE);  
  143.     DWORD ip;  
  144.     m_ip.GetAddress(ip);  
  145.     //初始化套接字DLL  
  146.     WSADATA wsa;  
  147.     if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){  
  148.         MessageBox("套接字初始化失败!");  
  149.         return;  
  150.     }  
  151.     //创建套接字  
  152.     if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){  
  153.         MessageBox("创建套接字失败!");  
  154.         WSACleanup();  
  155.         return;  
  156.     }  
  157.      ZeroMemory(&serverAddr,sizeof(serverAddr));  
  158.      serverAddr.sin_family = AF_INET;     
  159.      serverAddr.sin_addr.S_un.S_addr = htonl(ip);  
  160.      serverAddr.sin_port = htons(m_port);  
  161.      //注册感兴趣的网络事件  
  162.      if(WSAAsyncSelect(sock, m_hWnd, WM_NETWORK, FD_CONNECT | FD_READ | FD_CLOSE)==SOCKET_ERROR){  
  163.          MessageBox("注册网络事件失败!");  
  164.          closesocket(sock);  
  165.          WSACleanup();  
  166.      }  
  167.      msg.Format("Connecting to %s:%d/n",inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port));  
  168.      m_allmsg.SetSel(32767,32767);  
  169.      m_allmsg.ReplaceSel(msg);  
  170.      if(connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr))==SOCKET_ERROR){  
  171.          int err = WSAGetLastError();  
  172.          if(err==WSAEWOULDBLOCK){  
  173.              msg.Format("Waiting....../n");  
  174.              m_allmsg.SetSel(32767,32767);  
  175.              m_allmsg.ReplaceSel(msg);  
  176.          }else{  
  177.              MessageBox("无法连接到服务器!");  
  178.               closesocket(sock);  
  179.              WSACleanup();  
  180.          }  
  181.      }  
  182.      GetDlgItem(IDC_DISCONNECT)->EnableWindow(TRUE);  
  183.      GetDlgItem(IDC_SEND)->EnableWindow(TRUE);  
  184.      GetDlgItem(IDC_CHANGENAME)->EnableWindow(TRUE);  
  185.      GetDlgItem(IDC_CONNECT)->EnableWindow(FALSE);  
  186.      GetDlgItem(IDC_IP)->EnableWindow(FALSE);  
  187.      GetDlgItem(IDC_PORT)->EnableWindow(FALSE);  
  188.   
  189. }  
  190. LRESULT CClientDlg::OnNetwork(WPARAM wParam, LPARAM lParam)  
  191. {  
  192.     SOCKET s = (SOCKET)wParam;  
  193.     WORD netEvent = WSAGETSELECTEVENT(lParam);  
  194.     WORD error = WSAGETSELECTERROR(lParam);  
  195.     if(error!=0){  
  196.         msg.Format("Error code: %d/n",error);  
  197.         m_allmsg.SetSel(32767,32767);  
  198.         m_allmsg.ReplaceSel(msg);  
  199.         if(error==WSAECONNREFUSED){  
  200.             msg.Format("Connection refused./n");  
  201.             m_allmsg.SetSel(32767,32767);  
  202.             m_allmsg.ReplaceSel(msg);  
  203.             closesocket(sock);  
  204.             WSACleanup();  
  205.             GetDlgItem(IDC_DISCONNECT)->EnableWindow(FALSE);  
  206.             GetDlgItem(IDC_SEND)->EnableWindow(FALSE);  
  207.             GetDlgItem(IDC_CHANGENAME)->EnableWindow(FALSE);  
  208.             GetDlgItem(IDC_CONNECT)->EnableWindow(TRUE);  
  209.             GetDlgItem(IDC_IP)->EnableWindow(TRUE);  
  210.             GetDlgItem(IDC_PORT)->EnableWindow(TRUE);  
  211.         }  
  212.         return -1;  
  213.     }  
  214.     switch(netEvent){  
  215.         case FD_CONNECT:  
  216.             OnConnect(s);  
  217.             break;  
  218.         case FD_READ:  
  219.             OnRead(s);  
  220.             break;  
  221.         case FD_CLOSE:  
  222.             OnCloseSocket(s);  
  223.             break;  
  224.     }  
  225.     return 0;  
  226. }  
  227. void CClientDlg::OnConnect(SOCKET s)  
  228. {  
  229.     msg.Format("Connected to %s:%d/n",inet_ntoa(serverAddr.sin_addr),ntohs(serverAddr.sin_port));  
  230.     m_allmsg.SetSel(32767,32767);  
  231.     m_allmsg.ReplaceSel(msg);  
  232. }  
  233. void CClientDlg::OnRead(SOCKET s)  
  234. {  
  235.     static char buf[4096];  
  236.     int bytes;  
  237.     bytes = recv(s, buf, sizeof(buf), 0);  
  238.     if(bytes==SOCKET_ERROR || bytes==0){  
  239.         msg.Format("Socket error %d/n",WSAGetLastError());  
  240.         m_allmsg.SetSel(32767,32767);  
  241.         m_allmsg.ReplaceSel(msg);  
  242.         closesocket(s);  
  243.         return;  
  244.     }  
  245.     buf[bytes] = '/0';  
  246.     m_allmsg.SetSel(32767,32767);  
  247.     m_allmsg.ReplaceSel(buf);  
  248.     m_allmsg.SetSel(32767,32767);  
  249.     m_allmsg.ReplaceSel("/n");  
  250. }  
  251. void CClientDlg::OnCloseSocket(SOCKET s)  
  252. {  
  253.     closesocket(s);  
  254.     msg = "Connection closed./n ";  
  255.     m_allmsg.SetSel(32767,32767);  
  256.     m_allmsg.ReplaceSel(msg);  
  257.     GetDlgItem(IDC_DISCONNECT)->EnableWindow(FALSE);  
  258.     GetDlgItem(IDC_SEND)->EnableWindow(FALSE);  
  259.     GetDlgItem(IDC_CHANGENAME)->EnableWindow(FALSE);  
  260.     GetDlgItem(IDC_CONNECT)->EnableWindow(TRUE);  
  261.     GetDlgItem(IDC_IP)->EnableWindow(TRUE);  
  262.     GetDlgItem(IDC_PORT)->EnableWindow(TRUE);  
  263.     WSACleanup();  
  264. }  
  265. void CClientDlg::OnBnClickedSend()  
  266. {  
  267.     UpdateData(TRUE);  
  268.     int bytes;  
  269.     bytes = send(sock,(const char*)m_message,m_message.GetLength(),0);  
  270.     if(bytes==SOCKET_ERROR){  
  271.         int error = WSAGetLastError();  
  272.         if(error==WSAEWOULDBLOCK){  
  273.             msg = "Send failed for message: ";  
  274.             msg+=m_message;  
  275.         }else{  
  276.             msg.Format("Connection is down.");  
  277.         }  
  278.         m_allmsg.SetSel(32767,32767);  
  279.         m_allmsg.ReplaceSel(msg);  
  280.     }  
  281. }  
  282. void CClientDlg::OnBnClickedDisconnect()  
  283. {  
  284.     shutdown(sock,SD_SEND);  
  285. }  
  286. void CClientDlg::OnClose()  
  287. {  
  288.     //MessageBox("close");  
  289.     closesocket(sock);  
  290.     WSACleanup();  
  291.     CDialog::OnClose();  
  292. }  
  293. void CClientDlg::OnBnClickedQuit()  
  294. {  
  295.     SendMessage(WM_CLOSE);  
  296. }  
  297. void CClientDlg::OnBnClickedChangeName()  
  298. {  
  299.     UpdateData(TRUE);  
  300.     char buf[100];  
  301.     sprintf(buf,"name %s",m_nickname);  
  302.     if(send(sock,buf,strlen(buf),0)==SOCKET_ERROR){  
  303.         MessageBox("发送改名命令失败!");  
  304.         return;  
  305.     }  
  306.       
  307. }  

 

 

原理请参考我的课件: http://www.oakcms/network

0 0
原创粉丝点击