boost庫之udp client例項
阿新 • • 發佈:2019-02-13
//UdpLinkClient.h
//udp服務 #pragma once #include <boost/asio/ip/tcp.hpp> #include <boost/asio.hpp> #include <boost/function.hpp> #include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/shared_ptr.hpp> #include <boost/array.hpp> using boost::asio::ip::udp; #define UDP_DATA_PACKAGE_MAX_LENGTH 1024 //傳送資料回撥函式 typedef void (CALLBACK *SendDataCallback)(const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2);//設定工作引數 class UdpLinkClient { public: UdpLinkClient(char *pUrl,char *pServiceName,unsigned short usPort); virtual ~UdpLinkClient(void); // //------------------------------------------------------------------------------------- // 功能:傳送資料處理函式 // 引數:nReserved1,nReserved2:保留 // 返回:NULL:建立失敗 其他:物件地址 //------------------------------------------------------------------------------------- typedef boost::function<void* (const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2)> SendDataCallbackHandler; //開始 int Start(boost::asio::io_service& ioService); //停止 int Stop(); //傳送資料 int SendDataEx(udp::endpoint endpointRemote,char *pBuffer,int nBufferSize,SendDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2); //傳送資料 int SendData(char *pBuffer,int nBufferSize,bool bAsync); //啟用接收資料服務(自動) int AutoRecvData(); //啟用接收資料服務(人工) int MmanualRecvData(); //獲取伺服器端點 udp::endpoint & GetServerEndPoint(); //當收到對方端資料時,就進入本函式響應處理 void handleRecvData(const boost::system::error_code& error,std::size_t bytes_transferred); //當傳送資料給對方端成功之後響應處理 void handleSendData(char *pBuffer,int nBufferSize,const boost::system::error_code& error,std::size_t bytes_transferred); void handleSendDataInner(SendDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2,const boost::system::error_code& error,std::size_t bytes_transferred); //void handleSendData(boost::shared_ptr<std::string> strMessage,const boost::system::error_code& error,std::size_t bytes_transferred); static void WINAPI SendDataCallbackOuter(const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2); protected: //接收資料 void RecvDataProcess(); //是否停止服務 bool IsStop(); private: udp::socket *m_sockUdp; //伺服器的SOCKET udp::endpoint m_endpointRemote; //收到資料時的端點資訊 udp::endpoint m_endpointServer; //伺服器的端點資訊 boost::array<char,UDP_DATA_PACKAGE_MAX_LENGTH> m_recvBuf; //接收資料緩衝區 bool m_bStop; //停止服務 char m_szUrl[256]; //伺服器url char m_szServiceName[32]; //服務名,比如daytime,http unsigned short m_usPort; //埠 bool m_bReviceData; //是否接收過資料 bool m_bReviceServerUse; //是否啟用接收服務 };
//UdpLinkClient.cpp
//呼叫例項程式碼#include "StdAfx.h" #include "UdpLinkClient.h" #include <boost/exception/all.hpp> UdpLinkClient::UdpLinkClient(char *pUrl,char *pServiceName,unsigned short usPort) { m_bStop = false; m_usPort = usPort; m_sockUdp = NULL; memset(m_szUrl,0,sizeof(m_szUrl)); memset(m_szServiceName,0,sizeof(m_szServiceName)); if(pUrl != NULL) { strcpy(m_szUrl,pUrl); } if(pServiceName != NULL) { strcpy(m_szServiceName,pServiceName); } m_bReviceData = false; m_bReviceServerUse = false; } UdpLinkClient::~UdpLinkClient(void) { if(m_sockUdp != NULL) { m_sockUdp->close(); delete m_sockUdp; m_sockUdp = NULL; } } //開始 int UdpLinkClient::Start(boost::asio::io_service& ioService) { try { if(strlen(m_szServiceName) > 0) { //查詢連線的IP域名和埠 udp::resolver resolver(ioService); //udp::resolver::query query("www.google.com","http"); udp::resolver::query query(m_szUrl,m_szServiceName); m_endpointServer = *resolver.resolve(query); } else { m_endpointServer = udp::endpoint(boost::asio::ip::address_v4::from_string(m_szUrl), m_usPort); } m_sockUdp = new udp::socket(ioService); m_sockUdp->open(udp::v4()); m_sockUdp->set_option(boost::asio::socket_base::reuse_address(true)); //使用WSAIoctl設定UDP socket的工作模式,讓其忽略這個錯誤(Windows UDP socket recvfrom返回10054錯誤的解決辦法) BOOL bNewBehavior = FALSE; DWORD dwBytesReturned = 0; WSAIoctl(m_sockUdp->native(), SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL); //////////////////////////////////////////////////////////////////////////////////////////////////////// } catch (boost::exception& e) { //diagnostic_information(e); return -1; } m_bStop = false; m_bReviceData = false; m_bReviceServerUse = false; return 0; } //停止 int UdpLinkClient::Stop() { m_bStop = true; return 0; } //是否停止服務 bool UdpLinkClient::IsStop() { return m_bStop; } //獲取伺服器端點 udp::endpoint & UdpLinkClient::GetServerEndPoint() { return m_endpointServer; } void UdpLinkClient::SendDataCallbackOuter(const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2) { int i = 0; } //傳送資料 int UdpLinkClient::SendDataEx(udp::endpoint endpointRemote,char *pBuffer,int nBufferSize,SendDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2) { m_sockUdp->async_send_to(boost::asio::buffer(pBuffer,nBufferSize),endpointRemote,boost::bind(&UdpLinkClient::handleSendDataInner,this,pfunc,dwUserData1,dwUserData2,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); return 0; } //傳送資料 int UdpLinkClient::SendData(char *pBuffer,int nBufferSize,bool bAsync) { if(!m_bReviceData) { if(bAsync) { //非同步傳送 m_sockUdp->async_send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointServer,boost::bind(&UdpLinkClient::handleSendData,this,pBuffer,nBufferSize,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); } else { //同步傳送 std::size_t nSize = m_sockUdp->send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointServer); if(nSize > 0) { AutoRecvData(); } } } else { //更新了對方端點資訊 if(bAsync) { //非同步傳送 m_sockUdp->async_send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointRemote,boost::bind(&UdpLinkClient::handleSendData,this,pBuffer,nBufferSize,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); } else { //同步傳送 std::size_t nSize = m_sockUdp->send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointRemote); if(nSize > 0) { AutoRecvData(); } } } return 0; } //啟用接收資料服務(自動) int UdpLinkClient::AutoRecvData() { if(!m_bReviceServerUse) { RecvDataProcess(); m_bReviceServerUse = true; } return 0; } //啟用接收資料服務(人工) int UdpLinkClient::MmanualRecvData() { RecvDataProcess(); return 0; } //接收資料 void UdpLinkClient::RecvDataProcess() { //非同步接收資料 m_sockUdp->async_receive_from(boost::asio::buffer(m_recvBuf),m_endpointRemote,boost::bind(&UdpLinkClient::handleRecvData,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); } //當收到客戶端資料時,就進入本函式響應處理 void UdpLinkClient::handleRecvData(const boost::system::error_code& error,std::size_t bytes_transferred) { if(IsStop()) return; //如果沒有出錯 if(!error || error==boost::asio::error::message_size) { if(!m_bReviceData) { m_bReviceData = true; } if(bytes_transferred > UDP_DATA_PACKAGE_MAX_LENGTH) { //超過最大資料長度 return; } //列印接收的內容 char szTmp[UDP_DATA_PACKAGE_MAX_LENGTH] = {0}; memcpy(szTmp,m_recvBuf.data(),bytes_transferred); printf("%s\n",szTmp); //boost::shared_ptr<std::string> strMessage(new std::string("aaaaaa")); std::string strMessage = "bbbbbbbbb"; //SendData((char *)strMessage.data(),strMessage.size()); SendDataEx(m_endpointRemote,(char *)strMessage.data(),strMessage.size(),SendDataCallbackOuter,(int)this,0); //下一次接收 RecvDataProcess(); } } //當傳送資料給客戶端成功之後響應。 void UdpLinkClient::handleSendData(char *pBuffer,int nBufferSize,const boost::system::error_code& error,std::size_t bytes_transferred) { if(error != NULL) { //列印錯誤資訊 printf("%s", boost::system::system_error(error).what()); return; } AutoRecvData(); int n = 0; } void UdpLinkClient::handleSendDataInner(SendDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2,const boost::system::error_code& error,std::size_t bytes_transferred) { if(error != NULL) { //列印錯誤資訊 printf("%s", boost::system::system_error(error).what()); return; } if(pfunc != NULL) { pfunc(error,bytes_transferred,dwUserData1,dwUserData2); } int n = 0; } /* void UdpLinkClient::handleSendData(boost::shared_ptr<std::string> strMessage,const boost::system::error_code& error,std::size_t bytes_transferred) { int n = 0; } */
// UdpClient.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include "UdpLinkClient.h" #include <boost/thread/thread.hpp> //#define THREAD_RUN 1 //工作執行緒函式處理函式 bool g_WorkThreadExit = false; unsigned int __stdcall WorkThreadFunByDeviceServiceProcess(PVOID pParam) { boost::asio::io_service *pIoService = (boost::asio::io_service *)pParam; while(true) { if(g_WorkThreadExit) { break; } pIoService->poll(); Sleep(100); } return 0; } int main(int argc, char * argv[]) { boost::asio::io_service ioService; UdpLinkClient usUdpClient("127.0.0.1",NULL,7001); int nRet = usUdpClient.Start(ioService); if(nRet != 0) { return 0; } //傳送資料 nRet = usUdpClient.SendData("abcdedfg",8,true); #ifdef THREAD_RUN //執行緒poll等待 boost::thread thrd(WorkThreadFunByDeviceServiceProcess,&ioService); thrd.join(); g_WorkThreadExit = true; #else //阻塞等待,否則就直接退出了程式,io_service無法訊息迴圈處理 //io_service run也可以不呼叫,但該程序不能直接退出,需要阻塞。 ioService.run(); #endif usUdpClient.Stop(); ioService.stop(); return 0; }