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

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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值