boost庫之udp廣播例項
阿新 • • 發佈:2019-02-19
//UdpLinkServer.h
//UdpLinkServer.cpp//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); //接收資料回撥函式 typedef void (CALLBACK *RecvDataCallback)(const boost::system::error_code& error,char *pData,int nDataLength,char *pPeerIp,unsigned short usPeerPort,DWORD dwUserData1,DWORD dwUserData2); class UdpLinkServer { public: UdpLinkServer(unsigned short usPort,bool bBroadcast); virtual ~UdpLinkServer(void); //傳送資料回撥函式 boost function定義 typedef boost::function<void* (const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2)> SendDataCallbackHandler; /* 功能:設定接收資料回撥函式 引數:bAutoRecvData:是否自動接收資料;pfunc:接收資料回撥函式;dwUserData1:接收資料回撥函式使用者資料1;dwUserData2:接收資料回撥函式使用者資料2 返回值:無 */ void SetRecvDataCallback(bool bAutoRecvData,RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2); //開始 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); //獲取廣播端點 udp::endpoint & GetBroadcastEndPoint(); //接收資料處理(手動) void handleRecvDataByManual(RecvDataCallback pfunc=NULL,DWORD dwUserData1=0,DWORD dwUserData2=0); //當傳送資料給客戶端成功之後響應處理 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(RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2); //接收資料處理(自動) void handleRecvData(const boost::system::error_code& error,std::size_t bytes_transferred,RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2); //是否停止服務 bool IsStop(); private: udp::socket *m_sockUdp; //伺服器的SOCKET udp::endpoint m_endpointRemote; //收到資料時的端點資訊 udp::endpoint m_endpointBroadcast; //廣播端點資訊 boost::array<char,UDP_DATA_PACKAGE_MAX_LENGTH> m_recvBuf; //接收資料緩衝區 bool m_bStop; //停止服務 bool m_bBroadcast; //是否廣播 unsigned short m_usPort; //埠 bool m_bAutoRecvData; //是否自動接收資料,true,表示自動接收資料;false,表示外部手動呼叫函式接收資料 RecvDataCallback m_pfuncRecvDataCallback; //接收資料回撥函式 DWORD m_dwRecvDataCallbackUserData1; //接收資料回撥函式使用者資料1 DWORD m_dwRecvDataCallbackUserData2; //接收資料回撥函式使用者資料2 };
//廣播發送程式碼#include "StdAfx.h" #include "UdpLinkServer.h" #include <boost/exception/all.hpp> UdpLinkServer::UdpLinkServer(unsigned short usPort,bool bBroadcast) { m_bStop = false; m_bBroadcast = bBroadcast; m_usPort = usPort; m_sockUdp = NULL; m_bAutoRecvData = true; m_pfuncRecvDataCallback = NULL; m_dwRecvDataCallbackUserData1 = 0; m_dwRecvDataCallbackUserData2 = 0; } UdpLinkServer::~UdpLinkServer(void) { if(m_sockUdp != NULL) { m_sockUdp->close(); delete m_sockUdp; m_sockUdp = NULL; } } //設定接收資料回撥函式 void UdpLinkServer::SetRecvDataCallback(bool bAutoRecvData,RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2) { m_bAutoRecvData = bAutoRecvData; m_pfuncRecvDataCallback = pfunc; m_dwRecvDataCallbackUserData1 = dwUserData1; m_dwRecvDataCallbackUserData2 = dwUserData2; } //開始 int UdpLinkServer::Start(boost::asio::io_service& ioService) { try { if(m_bBroadcast) { //廣播 m_sockUdp = new udp::socket(ioService,udp::endpoint(udp::v4(),0)); m_sockUdp->set_option(boost::asio::socket_base::reuse_address(true)); m_sockUdp->set_option(boost::asio::socket_base::broadcast(true)); m_endpointBroadcast = udp::endpoint(boost::asio::ip::address_v4::broadcast(), m_usPort); } else { m_sockUdp = new udp::socket(ioService,udp::endpoint(udp::v4(),m_usPort)); if(!m_sockUdp->is_open()) { //埠被佔用 return -1; } m_sockUdp->set_option(boost::asio::socket_base::reuse_address(true)); } } catch (boost::exception& e) { return -1; } m_bStop = false; if(m_bAutoRecvData) { RecvDataProcess(m_pfuncRecvDataCallback,m_dwRecvDataCallbackUserData1,m_dwRecvDataCallbackUserData2); } return 0; } //停止 int UdpLinkServer::Stop() { m_bStop = true; return 0; } //是否停止服務 bool UdpLinkServer::IsStop() { return m_bStop; } //獲取廣播端點 udp::endpoint & UdpLinkServer::GetBroadcastEndPoint() { return m_endpointBroadcast; } void UdpLinkServer::SendDataCallbackOuter(const boost::system::error_code& error,std::size_t bytes_transferred,DWORD dwUserData1,DWORD dwUserData2) { int i = 0; } //傳送資料 int UdpLinkServer::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(&UdpLinkServer::handleSendDataInner,this,pfunc,dwUserData1,dwUserData2,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); return 0; } //傳送資料 int UdpLinkServer::SendData(char *pBuffer,int nBufferSize,bool bAsync) { if(!m_bBroadcast) { if(bAsync) { //非同步傳送 m_sockUdp->async_send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointRemote,boost::bind(&UdpLinkServer::handleSendData,this,pBuffer,nBufferSize,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); } else { //同步傳送 m_sockUdp->send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointRemote); } } else { //廣播 if(bAsync) { //非同步傳送 m_sockUdp->async_send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointBroadcast,boost::bind(&UdpLinkServer::handleSendData,this,pBuffer,nBufferSize,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); } else { //同步傳送 m_sockUdp->send_to(boost::asio::buffer(pBuffer,nBufferSize),m_endpointBroadcast); } } return 0; } //接收資料 void UdpLinkServer::RecvDataProcess(RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2) { //非同步接收資料 m_sockUdp->async_receive_from(boost::asio::buffer(m_recvBuf),m_endpointRemote,boost::bind(&UdpLinkServer::handleRecvData,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred,pfunc,dwUserData1,dwUserData2)); } //接收資料處理(手動),就進入本函式響應處理 void UdpLinkServer::handleRecvDataByManual(RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2) { if(IsStop()) return; //下一次接收 RecvDataProcess(pfunc,dwUserData1,dwUserData2); } //當收到客戶端資料時,就進入本函式響應處理 void UdpLinkServer::handleRecvData(const boost::system::error_code& error,std::size_t bytes_transferred,RecvDataCallback pfunc,DWORD dwUserData1,DWORD dwUserData2) { if(IsStop()) return; //如果沒有出錯 if(!error || error==boost::asio::error::message_size) { 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")); //SendData((char *)strMessage.data(),strMessage.size()); std::string strMessage = "aaaaaaaaaa"; SendDataEx(m_endpointRemote,(char *)strMessage.data(),strMessage.size(),SendDataCallbackOuter,(int)this,0); */ //回撥資料 if(pfunc != NULL) { pfunc(error,m_recvBuf.data(),bytes_transferred,(char *)m_endpointRemote.address().to_string().c_str(),m_endpointRemote.port(),dwUserData1,dwUserData2); } //下一次接收 RecvDataProcess(pfunc,dwUserData1,dwUserData2); } else { //出錯 if(pfunc != NULL) { pfunc(error,NULL,bytes_transferred,NULL,0,dwUserData1,dwUserData2); } } } //當傳送資料給客戶端成功之後響應。 void UdpLinkServer::handleSendData(char *pBuffer,int nBufferSize,const boost::system::error_code& error,std::size_t bytes_transferred) { int n = 0; } void UdpLinkServer::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()); } if(pfunc != NULL) { pfunc(error,bytes_transferred,dwUserData1,dwUserData2); } int n = 0; } /* void UdpLinkServer::handleSendData(boost::shared_ptr<std::string> strMessage,const boost::system::error_code& error,std::size_t bytes_transferred) { int n = 0; } */
// UdpbroastSender.cpp : 定義控制檯應用程式的入口點。 //Udpbroast Sender #include "stdafx.h" #include "UdpLinkServer.h" #include <boost/thread/thread.hpp> //裝置資訊 typedef struct tagDeviceInfo{ unsigned short usFunction; //功能碼 unsigned short usVersionFlag; //版本標記 unsigned int uiCompanyId; //企業id char szDeviceSerialNo[24]; //裝置序列號 unsigned short usServicePort; //資料服務埠 char szExtend[38]; //擴充套件 }DeviceInfo; //工作執行緒引數 typedef struct tagWorkThreadParameter{ boost::asio::io_service * pIoService; UdpLinkServer * pUdpService; }WorkThreadParameter; //工作執行緒函式處理函式 bool g_WorkThreadExit = false; int g_nBroastDataSendInteral = 5000; //廣播發送間隔,單位:毫秒 DeviceInfo g_diDeviceInfo = {0}; //裝置資訊 unsigned int __stdcall WorkThreadFunByDeviceServiceProcess(PVOID pParam) { int nn = 0; int nDataSize = sizeof(DeviceInfo); WorkThreadParameter *pAllParameter = (WorkThreadParameter *)pParam; while(true) { if(g_WorkThreadExit) { break; } //傳送資料 pAllParameter->pUdpService->SendData((char *)&g_diDeviceInfo,nDataSize,true); pAllParameter->pIoService->poll(); for(nn=g_nBroastDataSendInteral;nn>0; nn-=200) { if(g_WorkThreadExit) { break; } Sleep(200); } } return 0; } int main(int argc, char* argv[]) { boost::asio::io_service ioService; UdpLinkServer usUdpService(9090,true);//true,為廣播模式;false,非廣播模式 usUdpService.Start(ioService); g_diDeviceInfo.usFunction = 1; g_diDeviceInfo.usVersionFlag = 0x0001; strcpy(g_diDeviceInfo.szDeviceSerialNo,"ABCDEFG111111111"); g_diDeviceInfo.usServicePort = 9001; WorkThreadParameter wtpWorkThreadParameter; wtpWorkThreadParameter.pIoService = &ioService; wtpWorkThreadParameter.pUdpService = &usUdpService; //開啟執行緒 boost::thread thrd(WorkThreadFunByDeviceServiceProcess,&wtpWorkThreadParameter); //執行緒poll等待 thrd.join(); g_WorkThreadExit = true; usUdpService.Stop(); ioService.stop(); return 0; }
//廣播接收程式碼
// UdpbroastRevicer.cpp : 定義控制檯應用程式的入口點。
//Udpbroast Revicer
#include "stdafx.h"
#include "UdpLinkServer.h"
#include <boost/thread/thread.hpp>
//裝置資訊
typedef struct tagDeviceInfo{
unsigned short usFunction; //功能碼
unsigned short usVersionFlag; //版本標記
unsigned int uiCompanyId; //企業id
char szDeviceSerialNo[24]; //裝置序列號
unsigned short usServicePort; //資料服務埠
char szExtend[38]; //擴充套件
}DeviceInfo;
//工作執行緒函式處理函式
bool g_WorkThreadExit = false;
int g_nBroastDataSendInteral = 5000; //廣播發送間隔,單位:毫秒
DeviceInfo g_diDeviceInfo = {0}; //裝置資訊
unsigned int __stdcall WorkThreadFunByDeviceServiceProcess(PVOID pParam)
{
int nn = 0;
boost::asio::io_service * pIoService = (boost::asio::io_service *)pParam;
while(true)
{
if(g_WorkThreadExit)
{
break;
}
pIoService->poll();
for(nn=g_nBroastDataSendInteral;nn>0; nn-=200)
{
if(g_WorkThreadExit)
{
break;
}
Sleep(200);
}
}
return 0;
}
static void WINAPI BroastDeviceInfoRecvDataCallback(const boost::system::error_code& error,char *pData,int nDataLength,char *pPeerIp,unsigned short usPeerPort,DWORD dwUserData1,DWORD dwUserData2)
{
SYSTEMTIME sm;
GetLocalTime(&sm);
char szInfo[256] = {0};
DeviceInfo *pDeviceInfo = (DeviceInfo *)pData;
sprintf(szInfo,"%s %s:%d time:%04d-%02d-%0d %02d:%02d:%02d\n",pDeviceInfo->szDeviceSerialNo,pPeerIp,usPeerPort,sm.wYear,sm.wMonth,sm.wDay,sm.wHour,sm.wMinute,sm.wSecond);
printf(szInfo);
}
int main(int argc, char* argv[])
{
boost::asio::io_service ioService;
UdpLinkServer usUdpService(9090,false);
usUdpService.SetRecvDataCallback(true,BroastDeviceInfoRecvDataCallback,0,0);
usUdpService.Start(ioService);
//開啟執行緒
boost::thread thrd(WorkThreadFunByDeviceServiceProcess,&ioService);
//執行緒poll等待
thrd.join();
g_WorkThreadExit = true;
usUdpService.Stop();
ioService.stop();
return 0;
}