zoukankan      html  css  js  c++  java
  • 网络通信:单播、广播、组播

                                                                                                      网络通信:单播、广播、组播

    本文文件夹:

    一、网络通信的分类、他们的定义和特点。

    二、单播、广播、组播的传输信息的网络拓扑模型。

    三、单播、广播、组播的编程实例。


    一、网络通信的分类、他们的定义和特点。




    二、单播、广播、组播的传输信息的网络拓扑模型。

    (一)单播

    如图8-1 所看到的,网络中存在信息发送者Source,UserA 和UserC 提出信息需求,网络採用单播方式传输信息。

                                                    

    单播传输特点归纳例如以下:
    * Source 向每一个Receiver 地址发送一份独立的拷贝信息:packets for UserA;packets for UserC。
    * 网络为每一个Receiver 分别建立一条独立的数据传送通路:Source→ RouterB → RouterE → RouterD → UserA;Source → RouterB → RouterE → RouterF → UserC。
    单播方式下,网络中传输的信息量和需求该信息的用户量成正比,当需求该信息的用户量较大时,网络中将出现多份同样信息流。此时,带宽成为保证网络传输质量的重要瓶颈。
    单播方式较适合用户稀少的网络,不利于信息规模化发送。


    (二)广播

    如图8-2 所看到的,网络中存在信息发送者Source,UserA 和UserC 提出信息需求,网络採用广播方式传输信息。
                                

    广播传输特点归纳例如以下:
    * Source 向本网络广播地址发送且仅发送一份报文:packets for all the network。
    * 网络将报文拷贝传送到全部网段,无论是否须要,保证信息到达网络中全部的路由器和用户:UserB 也相同接收到一份拷贝。
    广播方式下,网络中全部用户都能接收到该信息,当网络中需求该信息的用户量非常小时,网络资源利用率将非常低,带宽浪费严重。不须要这些信息的用户也会受到影响。
    广播方式较适合用户稠密的网络,信息安全性和有偿服务得不到保障。 

    (三)多播

    如图8-3 所看到的,网络中存在信息发送者Source、UserA 和UserC 提出信息需求,网络採用组播方式传输信息。

                                                

    组播传输特点归纳例如以下:
    * Multicast group 称为组播组,使用一个IP 组播地址标识。UserA 和UserC 两个信息接收者,增加该组播组,从而能够接收发往该组播组的数据。
    * Source 称为组播源,向该组播组地址发送且仅发送一份报文:packets for the multicast group。网络传输过程中,同样的组播数据流在每一条链路上最多仅有一份。相比单播来说,使用组播方式传递信息,用户的添加不会显著添加网络的负载。
    * 依据组播组成员的分布情况,组播路由协议为多目的端的数据包转送建立树型路由。报文在尽可能远的分叉路口(如RouterE)才開始复制和分发,终于传送到组播组成员。相比广播来说,组播数据仅被传输到有接收者的地方,不会造成网络资源的浪费。
    * 网络中支持组播功能的路由器称为“组播路由器”,不仅提供组播路由功能,还可以在与网络用户连接的末梢网段上提供组成员管理功能(如RouterD 和RouterF)。同一时候,自己本身也可能是组播组成员。
    * 组播组中的成员是动态的,网络中的用户主机能够在不论什么时刻增加和离开组播组。组成员可能广泛分布在网络中的不论什么地方。组播源通常不会同一时候是其发送数据的接收者,即不属于其相应的目的组播组。
    * 一个源能够同一时候向多个组播组发送数据;多个源能够同一时候向一个组播组发送报文。
    * 为了帮助理解,能够类比收看某电视频道的节目。
    * 组播组是发送者和接收者之间的一个约定,如同电视频道。
    * 电视台是组播源,它向某频道内发送数据。
    * 电视机是接收者主机,观众打开电视机选择收看某频道的节目,表示主机增加某组播组;然后电视机播放该频道电视节目,表示主机接收到发送给这个组的数据。
    * 观众能够随时控制电视机的开关和频道间的切换,表示主机动态的增加或退出某组播组。


    三、单播、广播、组播的编程实例。

    (1)单播实例:(一个echoserver,能够同一时候和多个用户通信)

    head.h

    <span style="font-size:12px;">#ifndef _HEAD_H_
    #define _HEAD_H_
    
    #include<stdio.h>
    #include<string.h>
    #include<strings.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<arpa/inet.h> 
    #include<netinet/in.h>
    #include<error.h>
    #include<errno.h>
    #include<unistd.h>      //fork
    #include<sys/wait.h>
    
    #define SER_PORT 50004
    #define SER_IP "192.168.192.128"
    #define CLIENT_PORT 50000
    #define CLIENT_IP "192.168.192.128"
    
    #define BUFF_SIZE 100
    #define SIZE 20
    
    typedef struct _USER
    {
    	char name[SIZE];
    	char passwd[SIZE];
    }usr;
    #define sys_err(_msg)  error(EXIT_FAILURE,errno,_msg)
    /*errno是个全局变量,调用之后,能够在错误发生的情况下,也能输出——msg信息
    *作为调试用
    * */
    #endif
    </span>


    server.c

    <span style="font-size:12px;">#include "head.h"
    int socket_init()
    {
       int sockfd;
    	 struct sockaddr_in sockaddr;
       if((( sockfd=socket(AF_INET,SOCK_STREAM,0))==-1))
    		   sys_err("socket");
     
       bzero(&sockaddr,sizeof(sockaddr));
       sockaddr.sin_family=AF_INET;
       sockaddr.sin_port=htons(SER_PORT);
       sockaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    	printf("%d=====
    ",sockfd);
    
       if((bind(sockfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr)))==-1)
            sys_err("bind");
    
        listen(sockfd,5); //要懂得监听的作用,事实上就是建立一个缓冲队列,让创建的队列最多能够同意五个套接字进入
        return sockfd;
    }
    
    int do_echo(int connectfd)
    {
    	  char sbuf[BUFF_SIZE];
    	  char rbuf[BUFF_SIZE];
        int n;
    	printf("int the server ==========
    ");
    	while(1)
    	{
    		printf("===============in the do_echo
    ");
    		bzero(rbuf,BUFF_SIZE);
    		if((n=recv(connectfd,rbuf,BUFF_SIZE,0))==-1)
    		  	sys_err("recv");
    
    		if(n==0)     //假设接受为0,代表client已经断线,返回-1
    			return -1;
    
    		printf("server:rbuf==%s
    ",rbuf);
    		sprintf(sbuf,"%s %s",rbuf,"---------echo");
    
    		send(connectfd,sbuf,strlen(sbuf),0);
    	}
          
    	return ;
    }
    int main(int argc,const char * argv[])
    {
        //步骤:
    	/*
    	 *1 创建套接字socket();
    	 *2 与IP地址绑定bind();
    	 *3监听  listen();
    	 *4假设有链接,接受链接,进行三次握手accept();
    	 *5与client进行数据的传输read(),send();
    	 *6关闭套接字close(sockfd);
    	 * 
    	 *注意:要掌握熟练掌握各个接口的调用
    	 * 为了实现多client和服务器的交互,该怎么做
    	 * */
    
    	int sockfd;//具有基本属性的套接字描写叙述符
    	int connectfd;//进行三次握手之后的套接字描写叙述符
    
         sockfd=socket_init();
        //listen(sockfd,5); //要懂得监听的作用,事实上就是建立一个缓冲队列,让创建的将要
    		            //连接的套接字描写叙述符进队和出队
    /*
     *
     *
     *     The   accept()	system	 call  is  used  with  connection-based  socket  types
     *      (SOCK_STREAM, SOCK_SEQPACKET).  It extracts the first connection request on the
     *      queue  of  pending  connections for the listening socket, sockfd, creates a new
     *
     *
     * */
    	 pid_t pid;
    
        signal(SIGCHLD,SIG_IGN);
    
    	while(1)
    	{
    
            connectfd=accept(sockfd,NULL,NULL);   //一个服务器能够和多个client进程多次握手连接。 切记,connect()函数在UDP协议中也能够用,不是TCP的专用
    		  if(connectfd == -1)
    	         sys_err("accept");
    
    		if(-1==(pid=fork()))
    		{
    			perror("fork");
    		}
    		else if(pid==0)
    		{
    
    		printf("do_echo===%d
    ", do_echo(connectfd));
    		close(connectfd);    //将子进程从父进程拷贝到的套接字资源,关闭了
    			close(sockfd);
    		}
    	}
    close(connectfd);//父进程关闭自己的套接字
     	close(sockfd);
         return 0;
    
    }</span><span style="font-size:14px;">
    </span>

    (2)广播实例:

    sender.c  :

    <span style="font-size:14px;">#include"head.h"
    int main(int argc,const char * argv[])
    {
    
    	int sockfd;
    	struct sockaddr_in sockaddr;
    	char rbuf[BUFF_SIZE];
    	if(-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))    //因为TCP仅仅支持一对一通信,UDP能够一对一,一对多,多对一,多对多。因为这个广播。是多对多。所以仅仅能是SOCK_DGRAM
    
    		perror("socket");
    
    	bzero(&sockaddr,sizeof(sockaddr));
    	sockaddr.sin_family=AF_INET;
    	sockaddr.sin_port=htons(BRAOD_PORT);   //#define BRAOD_PORT 50001
    	sockaddr.sin_addr.s_addr=inet_addr(BRAOD_IP);//#define BRAOD_IP "192.168.1.255"
    
    	if(-1==bind(sockfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr)))
    		perror("bind");
    
    
         while(1)
    	 {
    		 bzero(&rbuf,sizeof(rbuf));
    		 recvfrom(sockfd,rbuf,BUFF_SIZE,0,(struct sockaddr*)&sockaddr,sizeof(sockaddr));
    		 printf("--------%s-------
    ",rbuf);
    	 }
    
    	 close(sockfd);
    	 return 0;
    }</span>


    (3)组播实例:

    sender.c :

    <span style="font-size:14px;">#include"head.h"
    int main(int argc ,const char * argv[])
    {
    	/*
    	 *创建组播发送方的步骤:
    	 *创建套接字
    	 *设置组播地址(可选)
    	 *发送数据
    	 *关闭套接字
    	 * */
    
    	int sockfd;
    	struct sockaddr_in multiaddr;
    	char sbuf[BUFF_SIZE]="hello,xiaowang....
    ";
        int n;
    	if(-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))
    	   perror("socket");
    
    	bzero(&multiaddr,sizeof(multiaddr));
        multiaddr.sin_family=AF_INET;
    	multiaddr.sin_port=htons(MULTI_PORT);   //#define MULTI_PORT 50002   仅仅要是用户自己定义端口就可以
    	multiaddr.sin_addr.s_addr=inet_addr(MULTI_IP);</span>
    <span style="font-size:14px;">            //#define MULTI_IP "224.4.4.4"  D类地址是组播地址224.0.0.1---239.255.255.254
    
    	while(1)
    	{
    		sleep(1);
    		if(-1==(n=sendto(sockfd,sbuf,strlen(sbuf),0,(struct sockaddr*)&multiaddr,sizeof(multiaddr))))
    			perror("sendto");
    
    		printf("in the sending..........
    ");
    	}	
        return 0;
    }</span>


    recevier.c :

    <span style="font-size:14px;">#include"head.h"
    int main(int argc,const char * argv[])
    {
          int sockfd;
    	  int n;
    	  char rbuf[BUFF_SIZE];
          struct  sockaddr_in groupaddr;
    
    	  //创建套接字
    	  if(-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))
    		  perror("socket");
    
    	  //增加组播
        struct ip_mreqn multiaddr;     //这些在Man 2 setsockopt  时在signal的有关描写叙述中能够查到的
    	  multiaddr.imr_multiaddr.s_addr=inet_addr(MULTI_IP);
    	  multiaddr.imr_address.s_addr=inet_addr(LOCAL_IP);
    	  multiaddr.imr_ifindex=0;
    
        //设置套接字同意发送组播信息的属性
          if(-1==setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&multiaddr,sizeof(multiaddr)))
    		      perror("setsockopt");
    
    
        //绑定组播地址
    	  bzero(&groupaddr,sizeof(groupaddr));
    	  groupaddr.sin_family=AF_INET;
    	  groupaddr.sin_port=htons(MULTI_PORT);
    	  groupaddr.sin_addr.s_addr=inet_addr(MULTI_IP);
    
    	  bind(sockfd,(struct sockaddr*)&groupaddr,sizeof(groupaddr));
    
          int t;
    	  while(1)
    	  {
    	//	  bzero(&rbuf,sizeof(rbuf));
               t=sizeof(groupaddr);
    		  if(-1==(n=recvfrom(sockfd,rbuf,BUFF_SIZE,0,(struct sockaddr*)&groupaddr,&t)))
    			  perror("recvfrom");
                sleep(1);  
    		  printf("%s-----------
    ",rbuf);
    	  }
    	  return 0;
    }
    </span>

     

    參考文献:http://www.xici.net/d79537500.htm


                                                                  未经同意,禁止转载

  • 相关阅读:
    new对象数组时的内存布局
    写程序取自己进程的AEP
    类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)
    测试 __try, __finally, __except(被__finally捕获的异常, 还会被上一级的__except捕获。反之不行)
    围观M$的new
    将258.369 double值转为内存表示(科学计数法)
    Broadcast Reveiver作用
    DEBUG模式下, 内存中的变量地址分析
    不包含SDK头文件, 补全API定义
    俄罗斯方块SDK版
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4357492.html
Copyright © 2011-2022 走看看