一、MFC网络编程
a)CAsyncSocket用于异步非阻塞类,用UDP通信;
b)CAsyncSocket的子类(派生类);Csocket同步阻塞类,用于TCP通信;
c)通信前,必须调用AfxSocketInit()进行初始化
二、CAsyncSocket类UDP通信
2.1 服务器端通信步骤:
a)在.h文件中创建CAsyncSocket类对象;
b)创建套接字CAsyncSocket::Create();
c)发送数据CAsyncSocket::SentTo();
d)关闭套接字CAsyncSocket::Close();
2.2 MFC界面
2.3 代码实例:
a)01_UDPServerDlg.h中添加CAsyncSocket对象
1 // 01_UDPServerDlg.h : 头文件 2 // 3 4 #pragma once 5 #include "afxcmn.h" 6 #include "afxwin.h" 7 8 9 // CMy01_UDPServerDlg 对话框 10 class CMy01_UDPServerDlg : public CDialogEx 11 { 12 // 构造 13 public: 14 CMy01_UDPServerDlg(CWnd* pParent = NULL); // 标准构造函数 15 16 // 对话框数据 17 enum { IDD = IDD_MY01_UDPSERVER_DIALOG }; 18 19 protected: 20 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 21 22 23 // 实现 24 protected: 25 HICON m_hIcon; 26 27 // 生成的消息映射函数 28 virtual BOOL OnInitDialog(); 29 afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 30 afx_msg void OnPaint(); 31 afx_msg HCURSOR OnQueryDragIcon(); 32 DECLARE_MESSAGE_MAP() 33 private: 34 //自定义添加代码,MFC界面对应控件变量 35 UINT peerPort; 36 UINT localPort; 37 CIPAddressCtrl addrCtrl; 38 CString sendBuf; 39 int sendLen; 40 CButton startButton; 41 CButton stopButton; 42 43 //套接字对象 44 CAsyncSocket socket; 45 public: 46 afx_msg void OnBnClickedButton1(); 47 afx_msg void OnTimer(UINT_PTR nIDEvent); 48 afx_msg void OnBnClickedButton2(); 49 };
b)01_UDPServerDlg.cpp中初始化各变量,并实现通信套接字的创建,接受及关闭
1 // 01_UDPServerDlg.cpp : 实现文件 2 // 3 4 #include "stdafx.h" 5 #include "01_UDPServer.h" 6 #include "01_UDPServerDlg.h" 7 #include "afxdialogex.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 13 14 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 15 16 class CAboutDlg : public CDialogEx 17 { 18 public: 19 CAboutDlg(); 20 21 // 对话框数据 22 enum { IDD = IDD_ABOUTBOX }; 23 24 protected: 25 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 26 27 // 实现 28 protected: 29 DECLARE_MESSAGE_MAP() 30 }; 31 32 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) 33 { 34 } 35 36 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 37 { 38 CDialogEx::DoDataExchange(pDX); 39 } 40 41 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 42 END_MESSAGE_MAP() 43 44 45 // CMy01_UDPServerDlg 对话框 46 47 48 49 CMy01_UDPServerDlg::CMy01_UDPServerDlg(CWnd* pParent /*=NULL*/) 50 : CDialogEx(CMy01_UDPServerDlg::IDD, pParent) 51 , peerPort(0) 52 , localPort(0) 53 , sendBuf(_T("")) 54 , sendLen(0) 55 { 56 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 57 } 58 59 void CMy01_UDPServerDlg::DoDataExchange(CDataExchange* pDX) 60 { 61 CDialogEx::DoDataExchange(pDX); 62 DDX_Text(pDX, IDC_EDIT1, peerPort); 63 DDX_Text(pDX, IDC_EDIT2, localPort); 64 DDX_Control(pDX, IDC_IPADDRESS1, addrCtrl); 65 DDX_Text(pDX, IDC_EDIT3, sendBuf); 66 DDX_Text(pDX, IDC_EDIT4, sendLen); 67 DDX_Control(pDX, IDC_BUTTON1, startButton); 68 DDX_Control(pDX, IDC_BUTTON2, stopButton); 69 } 70 71 BEGIN_MESSAGE_MAP(CMy01_UDPServerDlg, CDialogEx) 72 ON_WM_SYSCOMMAND() 73 ON_WM_PAINT() 74 ON_WM_QUERYDRAGICON() 75 ON_BN_CLICKED(IDC_BUTTON1, &CMy01_UDPServerDlg::OnBnClickedButton1) 76 ON_WM_TIMER() 77 ON_BN_CLICKED(IDC_BUTTON2, &CMy01_UDPServerDlg::OnBnClickedButton2) 78 END_MESSAGE_MAP() 79 80 81 // CMy01_UDPServerDlg 消息处理程序 82 83 BOOL CMy01_UDPServerDlg::OnInitDialog() 84 { 85 CDialogEx::OnInitDialog(); 86 87 // 将“关于...”菜单项添加到系统菜单中。 88 89 // IDM_ABOUTBOX 必须在系统命令范围内。 90 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 91 ASSERT(IDM_ABOUTBOX < 0xF000); 92 93 CMenu* pSysMenu = GetSystemMenu(FALSE); 94 if (pSysMenu != NULL) 95 { 96 BOOL bNameValid; 97 CString strAboutMenu; 98 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 99 ASSERT(bNameValid); 100 if (!strAboutMenu.IsEmpty()) 101 { 102 pSysMenu->AppendMenu(MF_SEPARATOR); 103 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 104 } 105 } 106 107 // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 108 // 执行此操作 109 SetIcon(m_hIcon, TRUE); // 设置大图标 110 SetIcon(m_hIcon, FALSE); // 设置小图标 111 112 // TODO: 在此添加额外的初始化代码 113 peerPort = 8888; 114 localPort = 9999; 115 sendBuf = _T("准备发送数据"); 116 sendLen = 0; 117 //把内容更新到对应的编辑区 118 UpdateData(FALSE); 119 120 addrCtrl.SetAddress(127, 0, 0, 1); 121 122 stopButton.EnableWindow(FALSE); 123 124 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE 125 } 126 127 void CMy01_UDPServerDlg::OnSysCommand(UINT nID, LPARAM lParam) 128 { 129 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 130 { 131 CAboutDlg dlgAbout; 132 dlgAbout.DoModal(); 133 } 134 else 135 { 136 CDialogEx::OnSysCommand(nID, lParam); 137 } 138 } 139 140 // 如果向对话框添加最小化按钮,则需要下面的代码 141 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, 142 // 这将由框架自动完成。 143 144 void CMy01_UDPServerDlg::OnPaint() 145 { 146 if (IsIconic()) 147 { 148 CPaintDC dc(this); // 用于绘制的设备上下文 149 150 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 151 152 // 使图标在工作区矩形中居中 153 int cxIcon = GetSystemMetrics(SM_CXICON); 154 int cyIcon = GetSystemMetrics(SM_CYICON); 155 CRect rect; 156 GetClientRect(&rect); 157 int x = (rect.Width() - cxIcon + 1) / 2; 158 int y = (rect.Height() - cyIcon + 1) / 2; 159 160 // 绘制图标 161 dc.DrawIcon(x, y, m_hIcon); 162 } 163 else 164 { 165 CDialogEx::OnPaint(); 166 } 167 } 168 169 //当用户拖动最小化窗口时系统调用此函数取得光标 170 //显示。 171 HCURSOR CMy01_UDPServerDlg::OnQueryDragIcon() 172 { 173 return static_cast<HCURSOR>(m_hIcon); 174 } 175 176 //发送按钮 177 void CMy01_UDPServerDlg::OnBnClickedButton1() 178 { 179 // TODO: 在此添加控件通知处理程序代码 180 181 //把编辑区的内容更新到对应的变量中 182 UpdateData(TRUE); 183 184 //创建UDP套接字 185 if (socket.Create(localPort, SOCK_DGRAM) ) 186 { 187 //启动定时器 处理 WM_TIMER消息 188 SetTimer(1, 500, NULL); 189 190 //开始按钮变灰 191 startButton.EnableWindow(FALSE); 192 //停止按钮恢复 193 stopButton.EnableWindow(TRUE); 194 } 195 else //套接字创建失败 196 { 197 MessageBox(_T("创建套接字失败")); 198 } 199 200 } 201 202 //定时器回调函数 203 void CMy01_UDPServerDlg::OnTimer(UINT_PTR nIDEvent) 204 { 205 // TODO: 在此添加消息处理程序代码和/或调用默认值 206 207 //组包,要发送的数据包 208 char buf[32] = { 0 }; 209 static int i = 0; 210 i++; 211 sprintf_s(buf, sizeof(buf), "%010d", i); 212 213 //获取对方的IP和端口 214 UpdateData(TRUE); //获取编辑区的值 215 BYTE a, b, c, d; 216 addrCtrl.GetAddress(a, b, c, d); 217 CString ip; 218 ip.Format(_T("%d.%d.%d.%d"), a, b, c, d); 219 220 //发送数据包 221 int len = socket.SendTo(buf, strlen(buf), peerPort, ip); 222 if (len > 0) 223 { 224 sendBuf = CString(buf); //char * -> CString 225 sendLen += len; 226 227 //把对应的值更新到编辑区 228 UpdateData(FALSE); 229 } 230 231 CDialogEx::OnTimer(nIDEvent); 232 } 233 234 235 void CMy01_UDPServerDlg::OnBnClickedButton2() 236 { 237 // TODO: 在此添加控件通知处理程序代码 238 sendBuf = _T("数据已经停止发送"); 239 UpdateData(FALSE); 240 241 socket.Close(); //关闭套接字 242 KillTimer(1); //关闭定时器 243 244 startButton.EnableWindow(TRUE); 245 stopButton.EnableWindow(FALSE); 246 }
2.3 客户端通信步骤:
a)在.h中创建CAsyncSocket类对象;
b)创建套接字CAsyncSocket::Create();
c)接受数据CAsyncSocket::ReceiveFrom();
d)关闭套接字CAsyncSocket::Close();
2.4 客户端MFC界面
2.3 01_UDPClientDlg.h中添加类
1 // 01_UDPClientDlg.h : 头文件 2 // 3 4 #pragma once 5 #include "afxwin.h" 6 7 8 // CMy01_UDPClientDlg 对话框 9 class CMy01_UDPClientDlg : public CDialogEx 10 { 11 // 构造 12 public: 13 CMy01_UDPClientDlg(CWnd* pParent = NULL); // 标准构造函数 14 15 // 对话框数据 16 enum { IDD = IDD_MY01_UDPCLIENT_DIALOG }; 17 18 protected: 19 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 20 21 22 // 实现 23 protected: 24 HICON m_hIcon; 25 26 // 生成的消息映射函数 27 virtual BOOL OnInitDialog(); 28 afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 29 afx_msg void OnPaint(); 30 afx_msg HCURSOR OnQueryDragIcon(); 31 DECLARE_MESSAGE_MAP() 32 private: 33 //自定义代码区 34 UINT peerPort; 35 UINT localPort; 36 CString peerIP; 37 CString recvBuf; 38 int recvLen; 39 CButton startButton; 40 CButton stopButton; 41 CAsyncSocket socket; 42 public: 43 afx_msg void OnBnClickedButton1(); 44 afx_msg void OnTimer(UINT_PTR nIDEvent); 45 afx_msg void OnBnClickedButton2(); 46 };
2.4 01_UDPClientDlg.cpp中初始化,并创建、接受、关闭套接字
1 // 01_UDPClientDlg.cpp : 实现文件 2 // 3 4 #include "stdafx.h" 5 #include "01_UDPClient.h" 6 #include "01_UDPClientDlg.h" 7 #include "afxdialogex.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 13 14 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 15 16 class CAboutDlg : public CDialogEx 17 { 18 public: 19 CAboutDlg(); 20 21 // 对话框数据 22 enum { IDD = IDD_ABOUTBOX }; 23 24 protected: 25 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 26 27 // 实现 28 protected: 29 DECLARE_MESSAGE_MAP() 30 }; 31 32 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) 33 { 34 } 35 36 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 37 { 38 CDialogEx::DoDataExchange(pDX); 39 } 40 41 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 42 END_MESSAGE_MAP() 43 44 45 // CMy01_UDPClientDlg 对话框 46 47 48 49 CMy01_UDPClientDlg::CMy01_UDPClientDlg(CWnd* pParent /*=NULL*/) 50 : CDialogEx(CMy01_UDPClientDlg::IDD, pParent) 51 , peerPort(0) 52 , localPort(0) 53 , peerIP(_T("")) 54 , recvBuf(_T("")) 55 , recvLen(0) 56 { 57 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 58 } 59 60 void CMy01_UDPClientDlg::DoDataExchange(CDataExchange* pDX) 61 { 62 CDialogEx::DoDataExchange(pDX); 63 DDX_Text(pDX, IDC_EDIT1, peerPort); 64 DDX_Text(pDX, IDC_EDIT2, localPort); 65 DDX_Text(pDX, IDC_EDIT3, peerIP); 66 DDX_Text(pDX, IDC_EDIT4, recvBuf); 67 DDX_Text(pDX, IDC_EDIT5, recvLen); 68 DDX_Control(pDX, IDC_BUTTON1, startButton); 69 DDX_Control(pDX, IDC_BUTTON2, stopButton); 70 } 71 72 BEGIN_MESSAGE_MAP(CMy01_UDPClientDlg, CDialogEx) 73 ON_WM_SYSCOMMAND() 74 ON_WM_PAINT() 75 ON_WM_QUERYDRAGICON() 76 ON_BN_CLICKED(IDC_BUTTON1, &CMy01_UDPClientDlg::OnBnClickedButton1) 77 ON_WM_TIMER() 78 ON_BN_CLICKED(IDC_BUTTON2, &CMy01_UDPClientDlg::OnBnClickedButton2) 79 END_MESSAGE_MAP() 80 81 82 // CMy01_UDPClientDlg 消息处理程序 83 84 BOOL CMy01_UDPClientDlg::OnInitDialog() 85 { 86 CDialogEx::OnInitDialog(); 87 88 // 将“关于...”菜单项添加到系统菜单中。 89 90 // IDM_ABOUTBOX 必须在系统命令范围内。 91 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 92 ASSERT(IDM_ABOUTBOX < 0xF000); 93 94 CMenu* pSysMenu = GetSystemMenu(FALSE); 95 if (pSysMenu != NULL) 96 { 97 BOOL bNameValid; 98 CString strAboutMenu; 99 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 100 ASSERT(bNameValid); 101 if (!strAboutMenu.IsEmpty()) 102 { 103 pSysMenu->AppendMenu(MF_SEPARATOR); 104 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 105 } 106 } 107 108 // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 109 // 执行此操作 110 SetIcon(m_hIcon, TRUE); // 设置大图标 111 SetIcon(m_hIcon, FALSE); // 设置小图标 112 113 // TODO: 在此添加额外的初始化代码 114 localPort = 8888; 115 peerPort = 9999; 116 peerIP = _T("127.0.0.1"); 117 118 recvBuf = _T("准备接收数据……"); 119 recvLen = 0; 120 121 //把值更新到对应的编辑区 122 UpdateData(FALSE); 123 124 stopButton.EnableWindow(FALSE); 125 126 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE 127 } 128 129 void CMy01_UDPClientDlg::OnSysCommand(UINT nID, LPARAM lParam) 130 { 131 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 132 { 133 CAboutDlg dlgAbout; 134 dlgAbout.DoModal(); 135 } 136 else 137 { 138 CDialogEx::OnSysCommand(nID, lParam); 139 } 140 } 141 142 // 如果向对话框添加最小化按钮,则需要下面的代码 143 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, 144 // 这将由框架自动完成。 145 146 void CMy01_UDPClientDlg::OnPaint() 147 { 148 if (IsIconic()) 149 { 150 CPaintDC dc(this); // 用于绘制的设备上下文 151 152 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 153 154 // 使图标在工作区矩形中居中 155 int cxIcon = GetSystemMetrics(SM_CXICON); 156 int cyIcon = GetSystemMetrics(SM_CYICON); 157 CRect rect; 158 GetClientRect(&rect); 159 int x = (rect.Width() - cxIcon + 1) / 2; 160 int y = (rect.Height() - cyIcon + 1) / 2; 161 162 // 绘制图标 163 dc.DrawIcon(x, y, m_hIcon); 164 } 165 else 166 { 167 CDialogEx::OnPaint(); 168 } 169 } 170 171 //当用户拖动最小化窗口时系统调用此函数取得光标 172 //显示。 173 HCURSOR CMy01_UDPClientDlg::OnQueryDragIcon() 174 { 175 return static_cast<HCURSOR>(m_hIcon); 176 } 177 178 void CMy01_UDPClientDlg::OnBnClickedButton1() 179 { 180 // TODO: 在此添加控件通知处理程序代码 181 182 //把编辑区的内容更新到对应的变量中 183 UpdateData(TRUE); 184 185 //创建UDP套接字 186 if (socket.Create(localPort, SOCK_DGRAM)) 187 { 188 //启动定时器 处理 WM_TIMER消息 189 SetTimer(1, 500, NULL); 190 191 //开始按钮变灰 192 startButton.EnableWindow(FALSE); 193 //停止按钮恢复 194 stopButton.EnableWindow(TRUE); 195 } 196 else //套接字创建失败 197 { 198 MessageBox(_T("创建套接字失败")); 199 } 200 } 201 202 //定时器回调函数 203 void CMy01_UDPClientDlg::OnTimer(UINT_PTR nIDEvent) 204 { 205 // TODO: 在此添加消息处理程序代码和/或调用默认值 206 207 UpdateData(TRUE); 208 209 char buf[32] = { 0 }; 210 int len = socket.ReceiveFrom(buf, sizeof(buf), peerIP, peerPort); 211 if (len > 0) 212 { 213 recvBuf = CString(buf); // char * -> CString 214 recvLen += len; 215 } 216 else 217 { 218 recvBuf = _T("停止接收数据"); 219 socket.Close(); 220 KillTimer(1); 221 stopButton.EnableWindow(FALSE); 222 startButton.EnableWindow(TRUE); 223 224 } 225 226 UpdateData(FALSE); 227 228 229 CDialogEx::OnTimer(nIDEvent); 230 } 231 232 233 void CMy01_UDPClientDlg::OnBnClickedButton2() 234 { 235 // TODO: 在此添加控件通知处理程序代码 236 237 recvBuf = _T("数据已经停止接收"); 238 UpdateData(FALSE); 239 240 KillTimer(1); //关闭定时器 241 socket.Close(); //关闭套接字 242 243 244 startButton.EnableWindow(TRUE); 245 stopButton.EnableWindow(FALSE); 246 }
2.5 实现效果