WinSock2 IP组播(多播)示例

来源:互联网 发布:python while循环假死 编辑:程序博客网 时间:2024/05/17 02:19

#include <winsock2.h>
#include <ws2tcpip.h>

#include <stdio.h>
#include <stdlib.h>

#pragma comment( lib, "ws2_32.lib" )

#define MCASTADDR "234.5.6.7"
#define MCASTPORT 25000
#define BUFSIZE   1024
#define DEFAULT_COUNT 500

BOOL bSender = FALSE,
  bLoopBack = FALSE;

DWORD dwInterface,
   dwMulticastGroup,
   dwCount;

short iPort;

void usage(char *progname)
{
 printf("usage: %s -s -m:str -p:int -i:str -l -n:int\n",progname);
 printf(" -s  Act as server (send data);otherwise\n");
 printf("    receive data.\n");
 printf(" -m:str Dotted decimal multicast IP address to join\n");
 printf("   The default group is: %s\n",MCASTADDR);
 printf(" -p:int Port number to use\n");
 printf("   The default port is: %d\n",MCASTPORT);
 printf(" -i:str Local interface to bind to; by default\n");
 printf("    use INADDRY_ANY\n");
 printf(" -l  Disable loopback\n");
 printf(" -n:int Number of messages to send/receive\n");
 ExitProcess(-1);
}

void ValidateArgs(int argc,char** argv)
{
 int i;
 
 dwInterface = INADDR_ANY;
 dwMulticastGroup = inet_addr(MCASTADDR);
 iPort = MCASTPORT;
 dwCount = DEFAULT_COUNT;

 for(i = 1; i < argc; i++)
 {
  if(( argv[i][0] == '-') || (argv[i][0] == '/'))
  {
   switch(tolower(argv[i][1]))
   {
   case 's':
    bSender = TRUE;
    break;
   case 'm':
    if( strlen(argv[i]) > 3 )
     dwMulticastGroup = inet_addr(&argv[i][3]);
    break;
   case 'i':
    if( strlen(argv[i]) > 3)
     dwInterface = inet_addr(&argv[i][3]);
    break;
   case 'p':
    if ( strlen(argv[i]) > 3)
     iPort = atoi(&argv[i][3]);
    break;
   case 'l':
    bLoopBack = TRUE;
    break;
   case 'n':
    dwCount = atoi(&argv[i][3]);
    break;
   default:
    usage(argv[0]);
    break;
   }
  }
 }
 return;
}

int main(int argc,char **argv)
{
 WSADATA  wsd;
 struct sockaddr_in local,
      remote,
      from;
 SOCKET   sock,sockM;
 char   recvbuf[BUFSIZE],
     sendbuf[BUFSIZE];
 int    len = sizeof(struct sockaddr_in),
     optval,
     ret;
 DWORD   i = 0;

 ValidateArgs(argc,argv);

 if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
 {
  printf("WSAStartup() Failed\n");
  return -1;
 }

 if(( sock = WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
  WSA_FLAG_MULTIPOINT_C_LEAF
  | WSA_FLAG_MULTIPOINT_D_LEAF
  | WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
 {
  printf("socket failed with: %d\n",WSAGetLastError());
  WSACleanup();
  return -1;
 }

 local.sin_family = AF_INET;
 local.sin_port = htons(iPort);
 local.sin_addr.s_addr = dwInterface;

 if( bind(sock,(struct sockaddr * ) &local,
  sizeof(local) ) == SOCKET_ERROR)
 {
  printf("bind failed with: %d\n",WSAGetLastError());
  closesocket(sock);
  WSACleanup();
  return -1;
 }

 remote.sin_family = AF_INET;
 remote.sin_port = htons(iPort);
 remote.sin_addr.s_addr = dwMulticastGroup;

 optval = 8;
 if( setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,
  (char*)& optval,sizeof(int)) == SOCKET_ERROR)
 {
  printf("setsockopt(IP_MULTICAST_TTL) failed: %d\n",WSAGetLastError());
  closesocket(sock);
  WSACleanup();
  return -1;
 }

 if( bLoopBack )
 {
  optval = 0;
  if( setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,
   (char*)& optval,sizeof(optval)) == SOCKET_ERROR)
  {
   printf("setsockopt(IP_MULTICAST_LOOP) failed: %d\n",WSAGetLastError());
   closesocket(sock);
   WSACleanup();
   return -1;
  }
 }
 
 if( (sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,
  sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH)) == INVALID_SOCKET)
 {
  printf("WSAJoinLeaf() failed: %d\n",WSAGetLastError());
  closesocket(sock);
  WSACleanup();
  return -1;
 }

 if( !bSender)
 {
  for(i = 0; i < dwCount; i++)
  {
   if((ret = recvfrom(sock,recvbuf,BUFSIZE,0,(struct sockaddr*)&from,&len)) == SOCKET_ERROR)
   {
    printf("recvfrom failed with: %d\n",WSAGetLastError());
    closesocket(sockM);
    closesocket(sock);
    WSACleanup();
    return -1;
   }
   recvbuf[ret] = 0;
   printf("RECV: '%s' from <%s>\n",recvbuf,inet_ntoa(from.sin_addr));
  }
 }
 else
 {
  for(i = 0; i < dwCount; i ++)
  {
   sprintf(sendbuf,"server 1:This is a test:%d",i);
   if(sendto(sock,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)&remote,sizeof(remote)) == SOCKET_ERROR)
   {
    printf("sendto failed with: %d\n",WSAGetLastError());

    closesocket(sockM);
    closesocket(sock);
    WSACleanup();
    return -1;
   }
   Sleep(500);
  }
 }

 closesocket(sock);
 WSACleanup();
 return -1;
}

 

这段代码来自《Windows网络编程》第一版中的例子,我做了些简单的处理,例子可以直接执行,方便大家理解和应用Windows组播。

记得我最早接触组播编程是在2002年,但是没有成功,这件事我一直很郁闷,现在呢总算能够游刃有余的驾驭Windows网络编程了,这么多年的汗水和努力总算没有白费。

这段代码中基本比较完整的展示了WinSock2种组播编程的每个方面,包括比较重要的TTL属性和回馈设置等。如果要用于广域网,那么就要注意bind部分的地址,最好是广域网的真实IP,对于使用路由器的,就要对路由器进行设置,对这个端口要放开,同时设置一条路由到服务器的直通路线,建议这种情况下最好配上防火墙,因为这相当于把服务器裸露在广域网上,因此防火墙是必要的。

原创粉丝点击