网络编程--广播&组播

广播
1.广播地址
如果用{netid, subnetid, hostid}( {网络ID,子网ID,主机ID})表示IPv4地址。那么有四种类型的广播地址,我们用-1表示所有比特位均为1的字段:
1). 子网广播地址:{netid, subnetid, -1}。这类地址编排指定子网上的所有接口。
2). 全部子网广播地址:{netid, -1, -1}。这类广播地址编排指定网络上的所有子网。
3). 网络广播地址:{netid, -1}。这类地址用于不进行子网划分的网络。
4). 受限广播地址:{-1, -1, -1}。路由器从不转发目的地址为255.255.255.255的IP数据
 
2.单播和广播的比较
单播IP数据报仅有通过目的IP地址指定的单个主机接受,子网上的其他主机均不受影响;
子网上所有未参加相应广播应用的所有机也必须沿协议栈一路向上完整的处理收取UDP广播数据报,直至该数据包经历UDP层时被丢弃为止
 
3.竞争状态
多个进程访问共享数据,但正确结构依赖于进程的执行顺序,这种情况我们称之为竞争状态(race condition)。竞争状态通常是线程编程中始终要注意的一个重要问题,因为在线程中有非常之多的数据需要共享,例如所有的全程变量。
在进行信号处理时,通常会出现各种类型的竞争状态。这是因为在我们的程序执行过程中,内核随时都会递交信号。
 
client.c
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <net/if.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#define SERVER_PORT 5555
#define CLIENT_PORT 5556 
#define MAXLINE 4096


int main(int argc,char *argv[])
{
    struct sockaddr_in localaddr;
    int confd;
    ssize_t len;
    char buf[MAXLINE];

    //1.创建一个socket
    confd=socket(AF_INET,SOCK_DGRAM,0);
    bzero(&localaddr,sizeof(localaddr));
    localaddr.sin_family=AF_INET;
    localaddr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
    localaddr.sin_port =htons(SERVER_PORT);

    int opt=-1;
    setsockopt(confd,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));
    int clientlen=sizeof(struct sockaddr_in);

    while(1){
        fgets(buf,sizeof(buf),stdin);
        sendto(confd,buf,strlen(buf),0,(struct sockaddr*)&localaddr,clientlen);
        len=recvfrom(confd,buf,sizeof(buf),0,NULL,0);
        write(STDIN_FILENO,buf,len);
    }    
    close(confd);
    return 0;
}    

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <ctype.h>
#include <net/if.h>

#define SERVER_PORT 5555 
#define CLIENT_PORT 5556 
#define MAXLINE 1024 

int main(void)
{
    int sockfd,i;
    ssize_t len;
    struct sockaddr_in serveraddr,clientaddr;
    char buf[MAXLINE];
    char ipstr[INET_ADDRSTRLEN];//16个字节
    socklen_t clientlen;

    //构造用于UDP通信的套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    //绑定广播监听
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family =AF_INET;
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    serveraddr.sin_port=htons(SERVER_PORT);
    //printf("%x
",INADDR_ANY);
    int opt=-1;
    setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));
    bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    
    /*构造client地址 */
    bzero(&clientaddr,sizeof(clientaddr));
    clientaddr.sin_family=AF_INET;
    clientaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    clientaddr.sin_port=htons(SERVER_PORT);
    
    clientlen=sizeof(struct sockaddr_in);
    while(1){    
        memset(buf,0,sizeof(buf));
        len=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&clientaddr,&clientlen);
        printf("Rec from client--IP: %s	 PORT %d
",
              inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ipstr,sizeof(ipstr)),
              ntohs(clientaddr.sin_port));
        i=0;
        while(i<len){
            buf[i]=toupper(buf[i]);
            i++;
        }
        buf[i]='';
        sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
    }
    close(sockfd);
    return 0;
}
多播
1.多播地址
1).IPv4多播地址和IPv6多播地址、IPv6多播地址
IPv4中的D类地址(从224.0.0.0到239.255.255.255)是多播地址。D类地址的低28位构成了多播组ID(group ID),而整个32位地址则称为组地址(group address)。
下面是多播地址映射到以太网地址的方法:
2).多播地址的范围
IPv6多播地址有一个4位的显示范围字段,该字段决定了多播数据报能够游走的范围。IPv6分组也有一个跳限字段,它限制分组被路由器转发的次数。下面是几个已经分配了的范围字段值:
  • 1:节点局部即局部于节点(node-local)
  • 2:链路局部即局部于链路(link-local)
  • 3:网点局部即局部于网点(site-local)
  • 8:组织局部即局部于组织(orgainization-local)
  • 14:全球(global)
其他值或者还没有分配或者已经保留。节点局部数据报禁止从接口输出,链路局部数据报不能被路由器转发,网点和组织的定义由该网点或组织的多播路由器管理员决定。
 
2.多播套接字选项
下面列出部分关于多播的套接字选项

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <ctype.h>
#include <net/if.h>

#define SERVER_PORT 5555 
#define CLIENT_PORT 5556 
#define MAXLINE 1024 
#define GROUP "239.0.0.2"

int main(void)
{
    int sockfd,i;
    ssize_t len;
    struct sockaddr_in serveraddr,clientaddr;
    char buf[MAXLINE];
    char ipstr[INET_ADDRSTRLEN];//16个字节
    socklen_t clientlen;
    struct ip_mreqn group;//设置组播

    //构造用于UDP通信的套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);

    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family =AF_INET;
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    serveraddr.sin_port=htons(SERVER_PORT);
    //printf("%x
",INADDR_ANY);
    bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    /*设置组地址*/
    inet_pton(AF_INET,GROUP,&group.imr_multiaddr);
    /*设置本地地址*/
    inet_pton(AF_INET,"0.0.0.0",&group.imr_address);
    group.imr_ifindex=if_nametoindex("eth0");//将网卡名转换成序号 等价 ip ad

    setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&group,sizeof(group));
    /*构造client地址 IP+端口*/
    bzero(&clientaddr,sizeof(clientaddr));
    clientaddr.sin_family=AF_INET;
    inet_pton(AF_INET,GROUP,&clientaddr.sin_addr.s_addr);
    clientaddr.sin_port=htons(CLIENT_PORT);
    while(1){    
    fgets(buf,sizeof(buf),stdin);    
    sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
    }
    close(sockfd);
    return 0;
}

client.c

#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <net/if.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#define SERVER_PORT 5555
#define CLIENT_PORT 5556 
#define MAXLINE 4096
#define GROUP "224.0.2.0"


int main(int argc,char *argv[])
{
    struct sockaddr_in serveraddr,localaddr;
    int confd;
    ssize_t len;
    char buf[MAXLINE];
    struct ip_mreqn group;//设置组播

    //1.创建一个socket
    confd=socket(AF_INET,SOCK_DGRAM,0);
    //2.初始化服务器地址
    bzero(&localaddr,sizeof(localaddr));
    localaddr.sin_family=AF_INET;
    //
    inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr.s_addr);
    localaddr.sin_port =htons(CLIENT_PORT);
    bind(confd,(struct sockaddr *)&localaddr,sizeof(localaddr));

    /*设置组地址*/
    inet_pton(AF_INET,GROUP,&group.imr_multiaddr);
    /*设置本地地址*/
    inet_pton(AF_INET,"0.0.0.0",&group.imr_address);
    group.imr_ifindex=if_nametoindex("eth0");//将网卡名转换成序号 等价 ip ad
    /*设置客户端加入多播组*/
    setsockopt(confd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));

    while(1){
        len=recvfrom(confd,buf,sizeof(buf),0,NULL,0);
        write(STDIN_FILENO,buf,len);
    }    
    close(confd);
    return 0;
}    
单播、广播、组播的区别小结
1.单播:
  主机之间一对一的通讯模式,网络中的交换机和路由器对数据只进行转发不进行复制。如果10个客户机需要相同的数据,则服务器需要逐一传送,重复10次相同的工作。但由于其能够针对每个客户的及时响应,所以现在的网页浏览全部都是采用单播模式,具体的说就是IP单播协议。网络中的路由器和交换机根据其目标地址选择传输路径,将IP单播数据传送到其指定的目的地。
  单播的优点:
  1)服务器及时响应客户机的请求
  2)服务器针对每个客户不通的请求发送不通的数据,容易实现个性化服务。
        
  单播的缺点:
  1)服务器针对每个客户机发送数据流,服务器流量=客户机数量×客户机流量;在客户数量大、每个客户机流量大的流媒体应用中服务器不堪重负。
  2)现有的网络带宽是金字塔结构,城际省际主干带宽仅仅相当于其所有用户带宽之和的5%。如果全部使用单播协议,将造成网络主干不堪重负。现在的P2P应用就已经使主干经常阻塞。而将主干扩展20倍几乎是不可能。
 
2.广播:
  主机之间一对所有的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),由于其不用路径选择,所以其网络成本可以很低廉。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。在数据网络中也允许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。
  广播的优点:
  1)网络设备简单,维护简单,布网成本低廉
  2)由于服务器不用向每个客户机单独发送数据,所以服务器流量负载极低。
        
  广播的缺点:
  1)无法针对每个客户的要求和时间及时提供个性化服务。
  2)网络允许服务器提供数据的带宽有限,客户端的最大带宽=服务总带宽。例如有线电视的客户端的线路支持100个频道(如果采用数字压缩技术,理论上可以提供500个频道),即使服务商有更大的财力配置更多的发送设备、改成光纤主干,也无法超过此极限。也就是说无法向众多客户提供更多样化、更加个性化的服务。
  3)广播禁止允许在Internet宽带网上传输。
 
  3.组播:
  主机之间一对一组的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。这样既能一次将数据传输给多个有需要(加入组)的主机,又能保证不影响其他不需要(未加入组)的主机的其他通讯。
  组播的优点:
  1)需要相同数据流的客户端加入相同的组共享一条数据流,节省了服务器的负载。具备广播所具备的优点。
  2)由于组播协议是根据接受者的需要对数据流进行复制转发,所以服务端的服务总带宽不受客户接入端带宽的限制。IP协议允许有2亿6千多万个组播,所以其提供的服务可以非常丰富。  
  3)此协议和单播协议一样允许在Internet宽带网上传输。
  
  组播的缺点:
  1)与单播协议相比没有纠错机制,发生丢包错包后难以弥补,但可以通过一定的容错机制和QOS加以弥补。
  2)现行网络虽然都支持组播的传输,但在客户认证、QOS等方面还需要完善,这些缺点在理论上都有成熟的解决方案,只是需要逐步推广应用到现存网络当中
 
原文地址:https://www.cnblogs.com/tla001/p/6608125.html