关于UDP 中的组播问题

http://blog.csdn.net/c395565746c/article/details/6016646

根据查询的资料来看,UDP广播只能在内网(同一网段)有效,而组播可以较好实现跨网段群发数据。

  • 简介

       IP网络传输方式共分为单播,组播(多播),广播三种。平时我们最常用的一对一的网络传输方式就是属于单播;而组播是一对多的传输方式,其中有个组播组的 概念,发送端将数据向一个组内发送,网络中的路由器通过底层的IGMP协议自动将数据发送到所有监听这个组的终端。至于广播则和组播有一些相似, 区别是路由器向子网内的每一个终端都投递一份数据包,不论这些终端是否乐于接收该数据包。

       相对于极度消耗网络带宽的广播来说(广播只能在内网广播),UDP组播有了很大的优化,只有终端加入到了一个广播组,UDP组播的数据才能被他接收到。 UDP组播是采用的无连接,数据报的连接方式,所以是不可靠的。也就是数据能不能到达接受端和数据到达的顺序都是不能保证的。但是由于UDP不用保证数据 的可靠性,所有数据的传送速度是很快的。

  • IP组播地址

        IP组播通信需要一个特殊的组播地址,IP组播地址是一组D类IP地址,范围从224.0.0.0 到 239.255.255.255。其中还有很多地址是为特殊的目的保留的。224.0.0.0到224.0.0.255的地址最好不要用,因为他们大多是 为了特殊的目的保持的(比如IGMP协议)

  • IGMP协议

        IGMP是IP组播的基础。在IP协议出现以后为了加入对组播的支持,IGMP产生了。IGMP所做的实际上就是告诉路由器,在这个路由器所在的子网内有 人对发送到某一个组播组的数据感兴趣,这样当这个组播组的数据到达后面,路由器就不会抛弃它,而是把他转送给所有感兴趣的客户。假如不同子网内的A和B要 进行组播通信,那么位于AB之间的所有路由器必须都要支持IGMP协议,否则AB之间不能进行通信。

  • UDP组播的基本步骤
  1. 建立socket
  2. socket和端口绑定
  3. 加入一个组播组
  4. 通过sendto / recvfrom进行数据的收发
  5. 关闭socket
C# Example
  • Send示例

            IPAddress ip = IPAddress.Parse("224.1.2.3");
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 1);
            IPEndPoint ipep = new IPEndPoint(ip, 5000);
            ......
            s.SendTo(buff, buff.Length, SocketFlags.None, ipep);
            ......
            s.Close();

  • Recv示例

            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);
            s.Bind(ipep);
            s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
                new MulticastOption(IPAddress.Parse("224.1.2.3"), IPAddress.Any));
            ......
            s.Receive(b, 4, SocketFlags.None);
            ......
            s.Close();

  • Example: UDPMulticast.7z  ftp://www.shgbit.com/UDPMulticast.7z
C++ Example

http://hi.baidu.com/jacky_jiajb/item/19f316ae4977cc9b1410731b

host.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
    struct sockaddr_in peeraddr;
    struct in_addr ia;
    int sockfd;
    char msg[100];
    unsigned socklen, n;
    struct hostent *group;
    struct ip_mreq mreq;
    
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
    bzero(&mreq, sizeof(struct ip_mreq));
    mreq.imr_multiaddr.s_addr = inet_addr("230.1.1.78");
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) {
      perror("setsockopt");
      exit(-1);
    }
    
    socklen = sizeof(struct sockaddr_in);
    memset(&peeraddr, 0, socklen);
    peeraddr.sin_family = AF_INET;
    peeraddr.sin_port = htons(7838);
    peeraddr.sin_addr.s_addr = htonl(INADDR_ANY);
   
    
    if (bind (sockfd, (struct sockaddr *) &peeraddr, sizeof(struct sockaddr_in)) == -1) {
      printf("Bind error\n");
      exit(0);
    }
    bzero(msg, sizeof(msg));
    n = recvfrom(sockfd, msg, 100, 0,(struct sockaddr *) &peeraddr, &socklen);
    printf("host recv:%s(%d)\n", msg, n);
}

 
cli.c:
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
  struct sockaddr_in peeraddr, myaddr;
  
  int sockfd;
  char msg[100]="i am toy";
  unsigned int socklen;
  
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  socklen = sizeof(struct sockaddr_in);
  
  bzero(&peeraddr, socklen);
  peeraddr.sin_family = AF_INET;
  peeraddr.sin_port = htons(7838);
  peeraddr.sin_addr.s_addr = inet_addr("230.1.1.78");
  if (sendto(sockfd, msg, strlen(msg), 0,(struct sockaddr *) &peeraddr, socklen) < 0) {
      printf("sendto error!\n");
      exit(3);
  }
  printf("'%s' send ok\n", msg);
}

 makefile见其他udp程序。
 
 组播和广播,从发送端来看就是IP地址不同,广播是最后一个为255,而组播是在239.0.0.0~239.255.255.255范围内的IP。从性能来说,广播要求所有节点都接受和处理,如果不需要则舍弃;而组播可以使部分主机进行处理。而接收端相对广播多了上面红色部分。

你可能感兴趣的:(C++)