注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lee198717的个人空间 https://home.eeworld.com.cn/space-uid-103677.html [收藏] [复制] [分享] [RSS]
日志

UDP组播通信程序框架

已有 5487 次阅读2013-2-26 11:01 |个人分类:MFC开发总结|

    UDP组播通信与UDP通信差别不大,程序基本框架一样,只要完成socket的配置和网络事件消息的注册即可实现首发功能。二者的差别仅在于配置程序的细小差别,其他基本程序模块是一样的:
对话框类头文件:
//step1:添加包含头文件和Winsock动态链接库
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
//step2:声明并编写WinSock版本校验程序
 int CheckWinsockVersion(void);
//step3:编写加入组播组程序,绑定本机端口,注册网络事件
 void JoinMulticastGroup(void);
附成员变量定义:
protected:
 HICON m_hIcon;
 SOCKET hSock;     //UDP套接字
 SOCKET mSock;     //多播套接字
 BOOL bFlag;      //设置套接字选项,使套接字为可重用端口地址
 SOCKADDR_IN Local;    //指向本地的IP地址与端口
 SOCKADDR_IN Remote;    //指向多播组的IP地址与端口
 SOCKADDR_IN From;    //指向数据来源的IP地址与端口
 int Fromlen;
//step4:注册网络消息及其网络事件
#define WM_SOCK_MSG WM_USER+1    //本程序只处理端口准备读事件
对话框类实现文件中:
char ReceiveBuf[1024]; //数据接收缓冲区缓存,定义在实现文件开头,作为全局变量
int CMulticastDlg::CheckWinsockVersion()
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 wVersionRequested = MAKEWORD(2,2);
 err = WSAStartup(wVersionRequested,&wsaData);
 if (err == 0)
 {
  if ((LOBYTE(wsaData.wVersion) == 2)&& (HIBYTE(wsaData.wVersion) == 2))
  return 0;
  WSACleanup();
  err = WSAVERNOTSUPPORTED;
 } 
 AfxMessageBox("Winsock DLL does not support requested API version.\r\n");
 return err;
}
void CMulticastDlg::JoinMulticastGroup()
{
 int nRet;
 DWORD cbRet;
 CString strERROR;
 DWORD dwLocalIP;
 DWORD dwMulticastIP;
 UpdateData(TRUE);
 //step5:初始化一个组播发送套接口
 hSock=WSASocket(AF_INET,SOCK_DGRAM,IPPROTO_UDP,
     (LPWSAPROTOCOL_INFO)NULL,0,WSA_FLAG_OVERLAPPED
     | WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF);
 if (hSock == INVALID_SOCKET)
 {
  strERROR.Format("WSASocket()failed,Err:%d\r\n",WSAGetLastError());
  AfxMessageBox(strERROR);
  return;
 }
 //step6:设置套接口选项,允许重用本地地址和端口
 bFlag=TRUE;
 setsockopt(hSock,SOL_SOCKET,SO_REUSEADDR,(char*)&bFlag,sizeof(bFlag));
 //step7:将套接字绑定到用户指定端口及默认的接口
 memset(&Local,0,sizeof(Local));
 Local.sin_family=AF_INET;
 Local.sin_port=htons((USHORT)m_edit_port);
 m_IPAddressCtrl_Local.GetAddress(dwLocalIP);
 Local.sin_addr.s_addr=inet_addr(DWORD2CSTRING(dwLocalIP));//指定本机IP
 bind(hSock,(struct sockaddr FAR *)&Local,sizeof(Local));
 //step8:设置套接口工作方式,设置多播数据报传播范围(生存时间TTL)
 nRet = WSAIoctl(hSock,SIO_MULTICAST_SCOPE,
     &m_edit_ttl,sizeof(int),
     NULL,0,&cbRet,NULL,NULL);
 if (nRet)
 {
  strERROR.Format("WSAioctl(SIO_MULTICAST_SCOPE)failed,Err:%d\r\n",WSAGetLastError());
  AfxMessageBox(strERROR);;
  UpdateData(FALSE);
  return;
 }
 //step9:设置套接口工作方式,设置多播返回(LOOKBACK)
 BOOL nLoopBack = m_check_loopback;//打开/关闭回播
 nRet = WSAIoctl(hSock,SIO_MULTIPOINT_LOOPBACK,&nLoopBack,sizeof(nLoopBack),
     NULL,0,&cbRet,NULL,NULL);
 if (nRet)
 {
  strERROR.Format("WSAioctl(SIO_MULTIPOINT_LOOPBACK)failed,Err:%d\r\n",WSAGetLastError());
  AfxMessageBox(strERROR);;
  return;
 }
 //step10:填写接收端套接口地址结构
 memset(&Remote,0,sizeof(Remote));
 Remote.sin_family=AF_INET;
 m_IPAddressCtrl_Multicast.GetAddress(dwMulticastIP);
 Remote.sin_addr.s_addr=inet_addr(DWORD2CSTRING(dwMulticastIP));
 Remote.sin_port=htons(m_edit_port);
 //step11:加入到指定的多播组,并指定为既作为发送者又作为接收者(JL_BOTH)
 mSock=WSAJoinLeaf(hSock,(sockaddr*)&Remote,sizeof(Remote),
     NULL,NULL,NULL,NULL,JL_BOTH);
 if(WSAAsyncSelect(mSock,m_hWnd,WM_SOCK_MSG,FD_READ)!=0)
  AfxMessageBox("注册网络消息及事件失败!"); //注册网络消息及其网络事件
}
LRESULT CMulticastDlg::OnSocketMsg(WPARAM wParam, LPARAM lParam)
{
 //消息回调函数,检索网络事件
 switch(WSAGETSELECTEVENT(lParam))
 {
  case FD_READ:
   UpdateData(TRUE);
   char achAddr[MAXADDRSTR] = {0};   
   Fromlen = sizeof(ReceiveBuf);
   unsigned long iLen = Fromlen;//用于强制类型转换
   m_edit_len = recvfrom(hSock,ReceiveBuf,1024,0,(sockaddr *)&From,&Fromlen); //缓冲区大小为1024字节,见ReceiveBuf的定义
   WSAAddressToString((struct sockaddr *)&From,sizeof(From),NULL,achAddr,&iLen);
   m_edit_from = (LPCTSTR)(achAddr[0]?achAddr:"??");
   m_edit_rxd += (LPCTSTR)ReceiveBuf;//显示发送端IP和端口,这里可以加入数据包解析代码
     UpdateData(FALSE);
  break;
 }
 return TRUE;
}
//如果程序运行时想要更改UDP组播参数,则调用这个函数即可(相当于先断开连接,然后在重新配置)
void CMulticastDlg::OnCheckJoin()
{
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 if (TRUE==m_check_join)
 {
  //加入UDP多播组
  if (0!=CheckWinsockVersion())
  {
   return;
  }
  JoinMulticastGroup();
 }
 else
 {
  //退出UDP多播组
  closesocket(mSock);
  closesocket(hSock);
  WSACleanup();
 } 
}
void CMulticastDlg::OnButtonSend()
{
 // TODO: Add your control notification handler code here
 //组播发送
 UpdateData(TRUE);
 if (TRUE==m_check_join)
 {
  CString strError;
  const char* strMessage=LPCTSTR(m_edit_txd);
  int nSize=m_edit_txd.GetLength()+1;
  int nRet = sendto(hSock,strMessage,nSize,0,(SOCKADDR *)&Remote,sizeof(Remote));
  if (nRet == SOCKET_ERROR)
  {
   strError.Format("WSASendTo()failed,Err:%d\n",WSAGetLastError());
   AfxMessageBox(strError);
  }
 }
 else
 {
  AfxMessageBox("请先加入多播组!");
 } 
}
void CMulticastDlg::OnButtonClear()
{
 // TODO: Add your control notification handler code here
 m_edit_rxd = "";
 UpdateData(FALSE);
}
void CMulticastDlg::OnDestroy()
{
 CDialog::OnDestroy();
 
 // TODO: Add your message handler code here
 if (mSock != NULL)
 {
  closesocket(mSock);
 }
 if (hSock)
 {
  closesocket(hSock);
 } 
 WSACleanup();
}
CString CMulticastDlg::DWORD2CSTRING(DWORD dwIP)
{
 CString strIP;
 strIP.Format("%d.%d.%d.%d",(0xFF000000&dwIP)>>24,(0xFF0000&dwIP)>>16,(0xFF00&dwIP)>>8,0xFF&dwIP);
 return strIP;
}
评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章