一、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 实现效果

