UDP广播通信
单播:一对一,TCP和UDP均可完成
广播:只能UDP完成。广播时发送方只发送一个数据包,但是网络上的交换机默认转发广播数据包到所有端口。路由器默认不转发任何广播数据包。故广播在局域网范围内。
组播:只有UDP可以完成。发送消息到同一个组播组的主机。视频电话、视频会议多采用。
广播IP地址:主机号全1。网络号正常
广播MAC地址:全1,即FF:FF:FF:FF:FF:FF
广播数据帧格式
处理过程:
网卡驱动程序对比自己的MAC地址与目的MAC地址,发现是广播MAC地址,统一接收并交给OS(IP层)。
IP层判断IP地址与自己是否一致。发现为IP地址为当前网段的广播地址,交给传输层
传输层根据端口,如果有对应的端口交给应用程序处理。否则丢弃数据包。
不管主机是否有进程接收广播消息,广播消息一定会被网卡收到并交个操作系统处理。会造成网络主机负担。
设置socket可以发送广播消息
int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
接收端绑定地址信息时,需要制定接收任意地址信息的数据包。
例子:
发送端广播一段信息,接收端接收。
注意:setsockopt为广播的目的应该是告知MAC地址为FF:FF:FF:FF:FF:FF 而广播的IP地址需要我们自己写上。即(网络号:全1主机号)。通过ifconfig获取。
发送端
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/tcp.h> #include<sys/socket.h> #include<sys/wait.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/time.h> int main(int argc, char **argv) { struct sockaddr_in s_addr; int sock; int addr_len; int len; char buff[128]; int yes; //UDP 创建socket if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } else { printf("create socket. "); } //设置socket为可发送广播消息 yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); s_addr.sin_family = AF_INET; s_addr.sin_port = htons(7838); if(argv[1]) { s_addr.sin_addr.s_addr = inet_addr(argv[1]); //参数1 广播地址 } else { printf("input sever ip! "); exit(0); } addr_len = sizeof(s_addr); strcpy(buff, "hello message"); //发送消息 len = sendto(sock, buff, strlen(buff), 0, (struct sockaddr *)&s_addr, addr_len); if(len < 0) { printf(" send error. "); exit(EXIT_FAILURE); } printf("send success. "); return 0; }
接收端
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/tcp.h> #include<sys/socket.h> #include<sys/wait.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/time.h> int main(int argc, char **argv) { struct sockaddr_in s_addr; struct sockaddr_in c_addr; int sock; socklen_t addr_len; int len; char buff[128]; //创建socket UDP if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } else { printf("create socket. "); } memset(&s_addr, 0, sizeof(struct sockaddr_in)); s_addr.sin_family = AF_INET; s_addr.sin_port = htons(7838); s_addr.sin_addr.s_addr = INADDR_ANY; //绑定IP地址 if((bind(sock, (struct sockaddr *)&s_addr, sizeof(s_addr))) == -1) { perror("bind"); exit(EXIT_FAILURE); } else { printf("bind address to socket. "); } addr_len = sizeof(c_addr); while(1) { //阻塞方式接收数据 len = recvfrom(sock, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&c_addr, &addr_len); if(len < 0) { perror("recvfrom"); exit(EXIT_FAILURE); } buff[len] = '