Linux网络编程[网络中的广播]

来源:互联网 发布:java web 日志 编辑:程序博客网 时间:2024/05/16 18:58

Linux网络编程[网络中的广播]

  1. 什么是广播
  2. 网络中广播地址
  3. 如何去进行广播
  4. 发送和接收广播实例Demo

什么是广播?

85-95年,这个10年出生的年轻人,对广播都不会陌生的,因为在童年或者青少年时期,某个阶段是由收音机来陪伴的,那收音机利用的是什么原理呢??最简单的就是,需要调频,把收音机设置到某个FM下,这样我们就可以听到某个频率下的广播….所以结合实际中的案例.广播是什么??我个人的理解是:广播是一种一对多的通信机制(类似群聊),它有着自己的必要前提条件:必须要对某个频率或者说是端口进行监听.这也就是注册的过程.如果不去监听的话.也需要一个解注册的过程.因为我主要是做android开发的.在android中也有自己的广播机制:sendbrocast,它需要的就是需要register和unregister.可以进行跨进程的通信等操作.
而我们这里所说的广播包含两个方面:
1:一对多的通信过程
2:它是通过广播地址发送数据报文来实现的(即特殊的ip地址)

在linux下,可以通过ifconfig来查看广播地址

这里写图片描述
从上面可以看到,我这边主机的广播地址就是192.168.2.255,广播地址是一个特殊的ip地址.广播发送者向这个地址发送大量的数据报文,而所有接受者只要和这个地址进行绑定,那么就全部能接收到这些报文,称为broadcast

网络中广播地址

广播地址
1:如果用{netID(A,B,C,D,E类型),subnetId,hostId}(网络id,子网id,主机id)表示ipv4地址,那么有四类的广播地址,我们用-1表示所有比特都为1的字段

2:子网广播地址:{netID,subnetID,-1}.这类地址编排制定子网上的所有接口,例如,如果我们对B类地址192.168采用8位子网ID,那么192.168.2.255将是192.168.2子网上所有接口的子网广播地址,路由器通常不会转发这类广播地址(一个子网一般都会有一个特定的广播地址)

3:全部子网的广播地址:{netID,-1,-1}.这类广播地址的编排制定网络上的所有子网,如果说这类地址曾被用过的话,那么现在已经是很少见的了

4:受限的广播地址:{-1,-1,-1}或者(255.255.255.255),路由器从来不转发目的地址255.255.255.255的ip数据报

如何去进行广播

通过套接字选项的设置来设置广播

套接字选项用于修饰套接字以及底层通讯协议的各种行为,函数setsockopt和getsockopt可以查看和设置套接字的各种选项  int getsockopt(int sockfd,int level,int optname,void* optval,socklen_t *optlen);  int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen);  设置正常返回0,出错返回-1

百度文库setsockopt函数的使用

百度文库getsockopt函数的使用

SO_BROADCAST选项控制着UDP套接字是否能够发送广播数据报,选项类型为int,非0意味着是,注意:只有UDP套接字可以使用这个选项,TCP是不能使用广播的(广播是udp发送方式下的一种特殊的方式)
代码:

int opt = 1;if((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0){  //错误处理}if(setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)) < 0){//错误处理}

通过setsockopt来设置其发送缓冲区和接收缓冲区的大小:SO_SNDBUF和SO_RCVBUF选项(设置发送缓冲区和接收缓冲区)

每一个套接字有一个发送缓冲区,和接收缓冲区,这两个缓冲区有底层的协议使用,接收缓冲区存放由协议接收的数据知道被应用程序读走,发送换从去存放应用写出的数据知道被协议发送出去,SO_SNDBUF和SO_RCVBUF选项分别控制发送和接收缓冲区的大小,他们的类型均为int,以字节为单位

相关代码:

  int opt;  if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0 ){//错误处理  } //获取默认的发送缓冲区域的大小 socklen_t len = sizeof(opt) ;     if(getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&opt,&len) < 0){    //错误处理} opt+=2048;  //将发送缓冲区的大小给进行扩大操作if(setsockopt(sockfd,SOL_SOCKET,SO_SNDBUF),&opt,sizeof(opt)) < 0 ){    //错误处理  }

代码部分:

/* * =========================================================================== * *       Filename:  broadcast_server.c *    Description:   *        Version:  1.0 *        Created:  2017年05月15日 21时17分37秒 *       Revision:  none *       Compiler:  gcc *         Author:   (),  *        Company:   * * =========================================================================== */#include<stdio.h>#include<stdlib.h>#include<sys/socket.h>#include<memory.h>#include<netdb.h>#include<signal.h>#include<unistd.h>int server_socket_fd;void sig_handler(int signo){  if(signo == SIGINT){    printf("signal interrupt occured\n");    close(server_socket_fd);    exit(EXIT_FAILURE);  }}void out_client_addr(struct sockaddr_in* addr_in){  char ip[16];  memset(ip,0,sizeof(ip));  inet_ntop(AF_INET,&addr_in->sin_addr.s_addr,ip,sizeof(ip));  int port;  port = ntohs(addr_in->sin_port);  printf("client:%s(%d)\n",ip,port);}int main(int argc,char *argv[]){ if(argc < 2){   printf("usage:%s port \n",argv[0]);   exit(EXIT_FAILURE); } if(signal(SIGINT,sig_handler) == SIG_ERR){   perror("register sigint error");   exit(EXIT_FAILURE); }/* * *udp下创建socket,(只有在udp下,才能设置广播发送的模式) * */ server_socket_fd = socket(AF_INET,SOCK_DGRAM,0); if(server_socket_fd < 0){   perror("create server_socket_fd error");   exit(EXIT_FAILURE); } /* *  *setsockopt设置广播类型  * */  int ret = 0; int opt = 0;// ret = setsockopt(server_socket_fd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)); //if(ret < 0){   //perror("set broadcast mode error");   //exit(EXIT_FAILURE);// }// memset(&ret,0,sizeof(ret));// memset(&opt,0,sizeof(opt)); /* *  *重新设置缓存  * */ socklen_t socklen  =sizeof(opt); ret = getsockopt(server_socket_fd,SOL_SOCKET,SO_RCVBUF,&opt,&socklen); if(ret < 0){   perror("get sock rev buf error");   exit(EXIT_FAILURE); } printf("RCVBUF:%d\n",opt); opt+=1024; memset(&ret,0,sizeof(ret)); ret = setsockopt(server_socket_fd,SOL_SOCKET,SO_RCVBUF,&opt,sizeof(opt)); if(ret < 0){   perror("set sock rcv buf error");   exit(EXIT_FAILURE); } printf("opt:%d\n",opt);/* * *进行端口绑定的操作 * */  struct sockaddr_in server_addr;  memset(&server_addr,0,sizeof(server_addr));  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(atoi(argv[1]));  server_addr.sin_addr.s_addr = INADDR_ANY;  if(bind(server_socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){     perror("bind error");     exit(EXIT_FAILURE);  }  struct sockaddr_in clientaddr;  socklen_t len = sizeof(clientaddr);  while(1){    memset(&clientaddr,0,sizeof(clientaddr));    char buff[1024];    //记住一定要去set一下buff,不然里面可能会存在一些莫名其妙的数据    memset(buff,0,sizeof(buff));    //接收数据    ssize_t  size = recvfrom(server_socket_fd,buff,sizeof(buff),0,(struct sockaddr*)&clientaddr,&len);    if(size < 0){      perror("recv error");    }else{      out_client_addr(&clientaddr);      printf("recv content:%s\n",buff);    }  }  return 0;}
/* * =========================================================================== * *       Filename:  broadcast_client.c *    Description:   *        Version:  1.0 *        Created:  2017年05月15日 22时10分09秒 *       Revision:  none *       Compiler:  gcc *         Author:   (),  *        Company:   * * =========================================================================== */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/socket.h>#include<sys/types.h>#include<netdb.h>#include<string.h>#include<memory.h>int client_sockfd;int main(int argc,char *argv[]){  if(argc < 3){    printf("usage:(%s)ip and port",argv[0]);    exit(EXIT_FAILURE);  }  client_sockfd  = socket(AF_INET,SOCK_DGRAM,0);  if(client_sockfd < 0){    perror("create client_sockfd error\n");    exit(EXIT_FAILURE);  }  int ret;  int opt=  1;  //采用广播形式去发送,注意第一个为sockfd  ret = setsockopt(client_sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));  if(ret != 0){    printf("setsockopt error\n");    close(client_sockfd);    exit(EXIT_FAILURE);  }  struct sockaddr_in server_addr;  memset(&server_addr,0,sizeof(server_addr));  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(atoi(argv[2]));  inet_pton(AF_INET,argv[1],&server_addr.sin_addr.s_addr);  printf("I will sendbroadcast\n");  char *info = "hello world";  ssize_t size = strlen(info) * sizeof(char);  //发送数据  if(sendto(client_sockfd,info,size,0,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0){    perror("send error");    exit(EXIT_FAILURE);  }else{    printf("send broadcast success");  }  close(client_sockfd);  return 0;}

以上就是代码部分,这里需要注意的就是关于setsockopt和getsockopt的时候返回的ret值,因为在某些时候,setsockopt往往可能返回的不是正确的数值
以上代码是经过精心调试后的,可以直接进run的.
欢迎访问博客

1 0