第14章 UDP编程(3)_利用UDP实现广播功能
3. 广播的介绍
(1)广播
①广播实现一对多的通信,如QQ群
②它通过向广播地址发送数据报文实现的
(2)SO_BROADCAST选项
①SO_BROADCAST选项控制着UDP套接字是否能发送广播数据报,选项的类型为int,非零意味着“是”。
②注意,该选项只有UDP套接字可以使用,TCP是不能使用广播的。
(3)其它选项:SO_SNDBUF和SO_RCVBUF选项
①每一个套接字有一个发送缓冲区和接收缓冲区,这两个缓冲区由底层协议使用。
②接收缓冲区存放由协议接收的数据直到被应用程序读走。发送缓冲区存放应用写出的数据直接被协议发送出去。
③SO_SNDBUF和SO_RCVBUF选项分别控制发送和接收缓冲区的大小,他们的类型均为int,以字节为单位。
(4)广播地址
①如果用{netID, subnetID, hostID}来表示IPv4地址,那么有四类的广播地址,用-1表示所有比特都为1的字段。
②子网广播地址:{netID, subnetID, -1}。这类地址编排指定子网上的所有接口。例如,如果我们对C类地址192.168采用8位子网ID,那么192.168.2.255将是192.168.2子网上所有接口的子网广播地址。路由器通常不转发这类广播。
③全部子网广播地址{netID,-1,-1}。这类广播地址编排指定网络上的所有子网。现在很少这样用。
④受限广播地址:{-1,-1,-1,-1}或{255,255,255,255}。路由器从不转发目的地址为255.255.255.255的IP数据报。
【编程实验】利用UDP发送广播(多对多或一对多)
//receiver.c
#include <netdb.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <memory.h>
int sockfd;
void sig_handler(int signo)
{
if(signo == SIGINT){
printf("receiver will exit\n");
close(sockfd);
exit(1);
}
}
int main(int argc, char* argv[])
{
if(argc < 2){
fprintf(stderr, "usage: %s port\n", argv[0]);
exit(1);
}
if(signal(SIGINT, sig_handler) == SIG_ERR){
perror("signal sigint error");
exit(1);
}
//创建套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0); //UDP协议
if(sockfd < 0){
perror("socket error");
exit(1);
}
//绑定地址,以便在指定的端口上接收广播
struct sockaddr_in recvAddr;
memset(&recvAddr, 0, sizeof(recvAddr));
recvAddr.sin_family = AF_INET; //IPv4
recvAddr.sin_port = htons(atoi(argv[1])); //port
recvAddr.sin_addr.s_addr = INADDR_ANY; //由系统指定IP
if(bind(sockfd, (struct sockaddr*)&recvAddr, sizeof(recvAddr)) < 0){
perror("bind error");
exit(1);
}
//接收广播消息
char buff[1024];
struct sockaddr_in sendAddr;
socklen_t len = sizeof(sendAddr);
while(1){
memset(buff, 0, sizeof(buff));
memset(&sendAddr, 0, sizeof(sendAddr));
if(recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr*)&sendAddr, &len) < 0){
perror("recvfrom error");
exit(1);
}else{
char ip[16];
inet_ntop(AF_INET, &sendAddr.sin_addr.s_addr, ip, sizeof(ip));
int port = ntohs(sendAddr.sin_port);
printf("%s(%d): %s\n", ip, port, buff);
}
}
}
/*输出结果
[root@localhost 14.udp]# gcc -o bin/broadcast src/broadcast.c
[root@localhost 14.udp]# bin/receiver
usage: bin/receiver port
[root@localhost 14.udp]# bin/receiver 8888
192.168.32.100(40894): hello world!
192.168.32.100(33915): hello world!
192.168.32.100(48427): hello world!
^Creceiver will exit
*/
//broadcast.c
#include <netdb.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main(int argc, char* argv[])
{
if(argc < 3){
fprintf(stderr, "usage: %s ip port\n", argv[0]);
exit(1);
}
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //UDP协议
if(sockfd < 0){
perror("socket error");
exit(1);
}
//设置为广播方式发送消息
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
struct sockaddr_in recvAddr; //指定广播的接收者地址信息。
memset(&recvAddr, 0, sizeof(recvAddr));
recvAddr.sin_family = AF_INET;
recvAddr.sin_port = htons(atoi(argv[2])); //注意,不指定IP(广播为255),只说明接收者的端口
inet_pton(AF_INET, argv[1], &recvAddr.sin_addr.s_addr);
printf("I will broadcast...\n");
char* info = "hello world!";
size_t size = strlen(info)* sizeof(char);
if(sendto(sockfd, info, size, 0, (struct sockaddr*)&recvAddr, sizeof(recvAddr)) < 0){
perror("sendto error");
exit(1);
}else{
printf("broadcast success\n");
}
close(sockfd);
return 0;
}
/*输出结果
* [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
* I will broadcast...
* broadcast success
* [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
* I will broadcast...
* broadcast success
* [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
* I will broadcast...
* broadcast success
*/

浙公网安备 33010602011771号