本帖最后由 ぉ沙皮狗的忧伤 于 2021-3-18 17:01 编辑
一、概念
数据包的发送方式只有一个接受方成为单播,如果同时发给局域网中的所有主机称为广播,只有用户使用UDP协议才能广播
广播地址,以172.18.21.1网段为例,最大的主机地址172.18.21.255代表该网段的广播地址
二、send_bt.c代码讲解
1、添加头文件
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <strings.h>
-
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
复制代码
2、建立数据报套接字,使用UDP
- //建立数据报套接字
- //参数1----地址族,网络地址族
- //参数2----套接字类型,SOCK_DGRAM使用UDP
- //参数3----protocol通常设置为0
- //返回值---成功返回socket ID,出错返回-1
- serfd = socket( AF_INET, SOCK_DGRAM, 0);
- if(serfd < 0){
- perror("socket failed!\n");
- exit(1);
- }
复制代码
3、打开广播
- int on = 1;
- //打开广播
- //参数1----socket套接字描述符
- //参数2----选项级别,SOL_SOCKET套接字级别上设置选项
- //参数3----选项名,SO_BROADCAST开启进程发送广播消息
- //参数4----存放选项值得缓冲区地址
- //参数5----缓冲区长度
- //返回值---成功返回0,失败返回-1
- ret = setsockopt( serfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- if(ret < 0){
- perror("setsockopt failed!\n");
- exit(1);
- }
复制代码
4、指定接收方IP,广播地址,端口
- //指定接收方IP为广播地址和端口
- struct sockaddr_in self;
- bzero( &self, sizeof(self));
-
- self.sin_family = AF_INET; //选择ipv4协议
- self.sin_port = htons(9999); //端口
- self.sin_addr.s_addr = inet_addr("172.18.21.255"); //广播地址
复制代码
5、从键盘读取数据并发送过去
- //写数据
- while(1){
- bzero( buf, 128);
- fgets( buf, 128, stdin);
-
- //发送数据
- //参数1-----套接字
- //参数2-----待发送数据的缓冲区
- //参数3-----缓冲区长度
- //参数4-----调用方式标志位,一般为0,将会改变sendto发送的形式
- //参数5-----指向目的的套接字地址
- //参数6-----指向地址的长度
- //返回值----成功,发送字节数,失败返回SOCKET_ERROR
- ret = sendto( serfd, buf, strlen(buf), 0, (struct sockaddr *)&self, sizeof(self));
- if(ret < 0){
- perror("send failed!\n");
- exit(1);
- }
- }
复制代码
三、recv_bt.c代码讲解1、添加头文件
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <strings.h>
-
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
复制代码
2、建立数据报套接字
- //2、建立数据报套接字
- //参数1----地址族,AF_INET网络地址族
- //参数2----套接字类型,SOCK_DGRAM使用UDP
- //参数3----procotol通常设置为0
- //返回值---成功返回socket id,失败返回-1
- serfd = socket( AF_INET, SOCK_DGRAM, 0);
复制代码
3、绑定本机IP和指定端口
- //绑定本机IP和指定端口
- struct sockaddr_in self;
- bzero( &self, sizeof(self));
-
- self.sin_family = AF_INET; //选择ipv4协议
- self.sin_port = htons(9999); //端口
- self.sin_addr.s_addr = htonl(INADDR_ANY); //内核自动绑定本地所有IP
-
- ret = bind( serfd, (struct sockaddr *)&self, sizeof(self));
- if(ret < 0){
- perror("bind failed!\n");
- exit(1);
- }
复制代码
4、读数据- char buf[1024];
- struct sockaddr_in cli;
- bzero( &cli,sizeof(cli));
-
- int len = sizeof(cli);
-
- //读数据:广播数据和单播数据
- while(1){
-
- bzero( buf, 1024);
- //接收数据
- //参数1-----套接字
- //参数2-----待发送数据的缓冲区
- //参数3-----缓冲区长度
- //参数4-----调用方式标志位,一般为0,将会改变recv接收的形式
- //参数5-----指向目的的套接字地址
- //参数6-----指向地址的长度
- //返回值----成功,接收字节数,失败返回SOCKET_ERROR
- ret = recvfrom( serfd, buf, 1023, 0, (struct sockaddr *)&cli, &len);
- if(ret < 0){
- perror("recvfrom failed!\n");
- exit(1);
- }
-
- printf("client ip = %s port = %d buf = %s\n", inet_ntoa(cli.sin_addr),\
- ntohs(cli.sin_port), buf);
- }
复制代码
四、使用gcc编译send_bt.c在Ubuntu上运行,使用交叉编译工具编译recv_bt.c在板卡上运行
测试
|