您的位置:首页 > 理论基础 > 计算机网络

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

2017-05-15 23:13 246 查看

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

什么是广播

网络中广播地址

如何去进行广播

发送和接收广播实例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的.

欢迎访问博客
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息