vc udp客户端异步通讯类封装
2015-09-12 18:07
281 查看
本章讲简单共享UDP异步通讯例程,udp是一种无连接、不保证数据是否传递成功,比起tcp通讯,它优势是传输数据快,因为它忽略了可靠传输机制。
所谓异步就是接受数据的时候不会产生阻塞效果,函数要不采用回调机制,要不就是直接返回。
工程是用基于VS2010 MFC下的。
新建通讯类UDPClientClass.h
在stdafx.h添加代码,将出现调试窗口
上面有三个按钮,ID号分别为IDC_BUTTON_OPEN,IDC_BUTTON_CLOSE,IDC_BUTTON_SEND
对应Resources.h内容如下:
在UDPClientDlg.h头文件内容如下:
在UDPCleintDlg.cpp里面内容如下
编译运行,并且打开网口调试工具,开UDP Server,监听1111端口,运行示意图如下:
所谓异步就是接受数据的时候不会产生阻塞效果,函数要不采用回调机制,要不就是直接返回。
工程是用基于VS2010 MFC下的。
新建通讯类UDPClientClass.h
#include <WinSock2.h> #define UDP_READ WM_USER + 3 #define READ_MAX_BUFFER 32 * 1024 class UDPClientClass { private: SOCKADDR_IN addrTo; SOCKET sckClient; WSABUF writeWsabuf; WSABUF readWsabuf; HWND curHwnd; public: UDPClientClass() { sckClient = INVALID_SOCKET; } ~UDPClientClass() { Close(); } BOOL Init() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return false; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { WSACleanup(); return FALSE; } return true; } /** 打开UDP 返回值为true则打开,否则无法发送数据 */ BOOL Open(const char *ip, UINT16 port, HWND hwnd) { if (!Init()) { return FALSE; } sckClient = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0); if (sckClient == INVALID_SOCKET) { return FALSE; } addrTo.sin_addr.S_un.S_addr = inet_addr(ip); addrTo.sin_family = AF_INET; addrTo.sin_port = htons(port); curHwnd = hwnd; //绑定句柄和UDP_READ消息 if (WSAAsyncSelect(sckClient, curHwnd, UDP_READ, FD_READ) == SOCKET_ERROR) { return FALSE; } int nRecvBuf =READ_MAX_BUFFER; //接受缓冲区设置为32K setsockopt(sckClient, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf,sizeof(int)); return TRUE; } /** 接受数据 data:是接受数据的首指针 addrFrom:服务端的IP地址端口结构指针 */ DWORD read(UINT8 *data, SOCKADDR_IN *addrFrom, WPARAM w, LPARAM l) { switch (LOWORD(l)) { case FD_READ: DWORD dwRead; DWORD dwFlag = 0; readWsabuf.len = READ_MAX_BUFFER; readWsabuf.buf = (char *)data; int len = sizeof(SOCKADDR); if (WSARecvFrom(sckClient, &readWsabuf, 1, &dwRead, &dwFlag, (SOCKADDR *)addrFrom, &len, NULL, NULL) == SOCKET_ERROR) { return 0; } return dwRead; } return 0; } /** 发送数据 */ int write(UINT8 *data, UINT32 len) { DWORD dwSend; writeWsabuf.buf = (char *)data; writeWsabuf.len = len; if (sckClient == INVALID_SOCKET)//如果没有打开UDP,则无法发送数据,直接返回0 { return 0; } if (WSASendTo(sckClient, &writeWsabuf, 1, &dwSend, 0, (SOCKADDR *)&addrTo, sizeof(SOCKADDR), NULL, NULL) == SOCKET_ERROR) { return 0; } return dwSend; } /** 判断是否打开UDP */ BOOL IsOpen() { if (sckClient != INVALID_SOCKET) { return TRUE; } return FALSE; } /** 关闭UDP */ void Close() { if (sckClient != INVALID_SOCKET) { WSACleanup(); sckClient = INVALID_SOCKET; } } };
在stdafx.h添加代码,将出现调试窗口
#define MY_DEBUG 1 #if MY_DEBUG #pragma comment( linker, "/subsystem:console /entry:wWinMainCRTStartup" ) #endif
上面有三个按钮,ID号分别为IDC_BUTTON_OPEN,IDC_BUTTON_CLOSE,IDC_BUTTON_SEND
对应Resources.h内容如下:
#define IDC_BUTTON_SEND 1000 #define IDC_BUTTON_OPEN 1001 #define IDC_BUTTON_CLOSE 1002
在UDPClientDlg.h头文件内容如下:
// UDPClientDlg.h : 头文件 // #pragma once #include "UDPClientClass.h" // CUDPClientDlg 对话框 class CUDPClientDlg : public CDialogEx { // 构造 private: UDPClientClass udpCliCls; public: CUDPClientDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_UDPCLIENT_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButtonSend(); afx_msg void OnBnClickedButtonClose(); afx_msg void OnBnClickedButtonOpen(); afx_msg LRESULT OnSock(WPARAM, LPARAM); //和UDP_READ绑定的函数 };
在UDPCleintDlg.cpp里面内容如下
// UDPClientDlg.cpp : 实现文件 // #include "stdafx.h" #include "UDPClient.h" #include "UDPClientDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CUDPClientDlg 对话框 CUDPClientDlg::CUDPClientDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CUDPClientDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CUDPClientDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CUDPClientDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON_SEND, &CUDPClientDlg::OnBnClickedButtonSend) ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CUDPClientDlg::OnBnClickedButtonClose) ON_BN_CLICKED(IDC_BUTTON_OPEN, &CUDPClientDlg::OnBnClickedButtonOpen) ON_MESSAGE(UDP_READ, &CUDPClientDlg::OnSock) //消息绑定UDP_READ END_MESSAGE_MAP() // CUDPClientDlg 消息处理程序 BOOL CUDPClientDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(true); GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(false); GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(false); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CUDPClientDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 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 { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CUDPClientDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } LRESULT CUDPClientDlg::OnSock(WPARAM wParam, LPARAM lParam) { UINT8 *data = new UINT8[READ_MAX_BUFFER]; SOCKADDR_IN addrFrom; UINT32 len = udpCliCls.read(data, &addrFrom, wParam, lParam); if (len > 0) { printf("***UDP client recv\r\n", len); printf("ip = %08x port = %5d\r\n", addrFrom.sin_addr.S_un.S_addr, ntohs(addrFrom.sin_port)); for (DWORD i = 0; i < len; i++) { printf("%d=%02x\r\n", i, data[i]); } } delete data; data = NULL; return 0; } void CUDPClientDlg::OnBnClickedButtonOpen() { // TODO: 在此添加控件通知处理程序代码 if (!udpCliCls.IsOpen()) { if (udpCliCls.Open("127.0.0.1", 1111, this->m_hWnd)) { GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(false); GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(true); GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(true); } } } void CUDPClientDlg::OnBnClickedButtonClose() { // TODO: 在此添加控件通知处理程序代码 if (udpCliCls.IsOpen()) { udpCliCls.Close(); GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(true); GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(false); GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(false); } } void CUDPClientDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 UINT8 a[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; if (udpCliCls.IsOpen()) { if (udpCliCls.write(a, 10)) { printf("***UDP client send\r\n", a); for (DWORD i = 0; i < 10; i++) { printf("%d=%02x\r\n", i, a[i]); } } } }
编译运行,并且打开网口调试工具,开UDP Server,监听1111端口,运行示意图如下:
相关文章推荐
- K均值聚类(C++)
- [Java] HashMap的实现
- 软件工程的实践项目的自我目标
- iOS 虚拟定位方法
- 【网络】(四)网络相关函数使用简介
- COCI CONTEST #1 18.10.2014 T3 PIRAMIDA
- Git Ignore 的使用
- Java设计模式——工厂方法模式
- web.xml 中spring-servlet.xml 和 application.xml 配置位置及含义
- centOS设置zookeeper开机自动启动
- Java操作XML文件(写)
- I2C学习笔记二
- 如何判断当前网络状况
- 全排列总结
- 快速了解Android项目
- html5+css3项目 (企业网站之集团活动)
- [LeetCode] Word Break
- 阿里云配置
- 在线重定义
- java_集合01