概述
socket默认不支持发送广播报文,通过SO_BROADCAST
选项的设置,开启广播发送功能。简单总结一下广播报文收发的规律:
- 客户端socket开启
SO_BROADCAST
选项后才能发送广播报文,否则调用sendto
会报错 - 服务端无需开启
SO_BROADCAST
- 服务端
bind
单播地址时,不接受客户端的广播数据,仅接受目的地址为单播地址的报文 - 服务端
bind
广播地址时,接收客户端的广播数据 - 服务端
bind
通用地址INADDR_ANY
时,既能够接收客户端的单播报文,也能接收广播报文
服务端代码
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
int
main(int argc, char **argv)
{
int sockfd, opt, n;
struct sockaddr_in servaddr, cliaddr;
char buff[256];
socklen_t cliaddrlen = sizeof(struct sockaddr_in);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
bzero(&cliaddr, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);// --> network short
//inet_pton(AF_INET, "192.168.157.144", &(servaddr.sin_addr));
servaddr.sin_port = htons(13);
/*
opt = 1;
if ((n = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) < 0) {
perror("setsockopt eror");
}
*/
if ((n = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) < 0) {
perror("bind failed\n");
}
for( ; ; ) {
recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&cliaddr, &cliaddrlen);
printf("recv udp from %s\n", inet_ntoa(cliaddr.sin_addr));
}
return 0;
}
客户端代码
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
int
main(int argc, char **argv)
{
int sockfd, n, opt;
char recvline[256], sendbuf[256];
struct sockaddr_in servaddr, cliaddr;
if (argc != 2) {
printf("usage: %s <IPaddress>\n", argv[0]);
return 0;
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket error\n");
}
bzero(&servaddr, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0) {
perror("inet_pton error");
}
bzero(&cliaddr, sizeof(struct sockaddr_in));
cliaddr.sin_family = AF_INET;
if (inet_pton(AF_INET, "192.168.157.144", &cliaddr.sin_addr) < 0) {
perror("inet_pton error for cliaddr\n");
}
if ( (n = bind(sockfd, (struct sockaddr *)&cliaddr, sizeof(struct sockaddr))) < 0 ) {
perror("bind failed");
}
strncpy(sendbuf, "hello", sizeof(sendbuf));
opt = 1;
if ( (n = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) < 0) {
perror("sesockopt failed");
}
if ( (n = sendto(sockfd, sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr))) < 0) {
perror("sendto failed");
}
return 0;
}