一、UDP 通信图解
UDP通信、本地套接字_呵呵哒( ̄▽ ̄)"的博客-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/132523536?spm=1001.2014.3001.5501
#include <sys/types.h>
#include <sys/socket >
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);- 参数:- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度- flags : 0- dest_addr : 通信的另外一端的地址信息- addrlen : 地址的内存大小ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);- 参数:- sockfd : 通信的fd- buf : 接收数据的数组- len : 数组的大小- flags : 0- src_addr : 用来保存另外一端的地址信息,不需要可以指定为NULL- addrlen : 地址的内存大小
二、广播
广播:向子网中多态计算机发送消息,并且子网中所有计算机都可以接收到发送方发送的消息,每个广播消息都包含一个特殊的IP地址,这个IP中子网内主机标志部分的二进制全部为1
🐞 a.只能在局域网中使用
🐞 b.客户端需要绑定服务器广播使用的端口,才可以接收到广播信息
// 设置广播属性的函数
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);- sockfd : 文件描述符- level : SOL_SOCKET- optname : SO_BROADCAST- optval : int类型的值,为1表示允许广播- optlen : optval的大小
什么是广播?
- ① 数据包发送方式只有一个接受方,称为单播
- ② 如果同时发给局域网中的所有主机,称为广播
- ③ 只有用户数据报(使用UDP协议)套接字才能广播
广播地址
- ① 一个网络内主机号全为1的IP地址为广播地址
- ② 发到该地址的数据包被所有的主机接收
- ③ 255.255.255.255在所有网段中都代表广播地址
>>实验一
bro_server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>int main () {// 1.创建一个通信的socketint fd = socket(PF_INET, SOCK_DGRAM, 0);if(fd == -1) {perror("socket");exit(-1);}// 2.设置广播属性int op = 1;setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));// 3.创建一个广播的地址struct sockaddr_in broaddr;broaddr.sin_family = AF_INET;broaddr.sin_port = htons(9999);// broaddr.sin_addr.s_addr = inet_addr("192.168.90.255");inet_pton(AF_INET,"192.168.90.255",&broaddr.sin_addr.s_addr);//设置广播地址,必须为本机/虚拟机的广播地址才行// 3.通信int num = 0;while (1) {char sendBuf[128];sprintf(sendBuf,"hello,client....%d\n",num++);// 发送数据sendto(fd,sendBuf,strlen(sendBuf) + 1,0,(struct sockaddr*)&broaddr,sizeof(broaddr));printf("广播的数据:%s\n",sendBuf);sleep(1);}close(fd);return 0;
}
bro_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>int main () {// 1.创建一个通信的socketint fd = socket(PF_INET,SOCK_DGRAM,0);if(fd == -1) {perror("socket");exit(-1);}// 2.客户端绑定本地的IP和端口struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = INADDR_ANY;int ret = bind(fd,(struct sockaddr *)&addr,sizeof(addr));if(ret == -1) {perror("bind");exit(-1);}// 3.通信while(1) {char buf[128];// 接收数据int num = recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);printf("server say: %s\n",buf);}close(fd);return 0;
}
>>实验二
① 安装wireshark:sudo apt install wireshark
② ifconfig 查看广播地址
③ 运行wireshark,输入host 192.168.90.255
④ 打开另一台虚拟机,IP地址为:192.168.90.132
⑤ 执行以下命令
⑥ 在第一个终端输入
sender.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superser of previos */
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;int main(int argc, char *argv[]) {int fd = -1;Addr_in peeraddr;socklen_t peerlen = sizeof(peeraddr);char buf[BUFSIZ] = {};/* 参数检查 */if(argc < 3) {fprintf(stderr, "Usage: %s <IP> <Port>\n", argv[0]);exit(EXIT_FAILURE);}/* 创建套接字 */if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ErrExit("socket");/* 允许广播 */int on = 1;setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));/* 设置通信结构体 */peeraddr.sin_family = AF_INET;peeraddr.sin_port = htons(atoi(argv[2]));if(!inet_aton(argv[1], &peeraddr.sin_addr)) {fprintf(stderr, "Invalid IP address\n");exit(EXIT_FAILURE);}while(1) {fgets(buf,BUFSIZ,stdin);sendto(fd, buf, strlen(buf)+1, 0, (Addr*)&peeraddr, peerlen);}return 0;
}
receiver.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superser of previos */
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;int main(int argc, char *argv[]) {int fd = -1;Addr_in myaddr,peeraddr;socklen_t peerlen = sizeof(peeraddr);char buf[BUFSIZ] = {};/* 参数检查 */if(argc < 3) {fprintf(stderr, "Usage: %s <IPaddress> <port>\n", argv[0]);exit(EXIT_FAILURE);}/* 创建套接字 */if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0) ErrExit("socket");/* 设置通信结构体 */myaddr.sin_family = AF_INET;myaddr.sin_port = htons(atoi(argv[2]));if(!inet_aton(argv[1], &myaddr.sin_addr)) {fprintf(stderr, "Invalid address\n");exit(EXIT_FAILURE);}/* 绑定通信结构体 */if(bind(fd, (Addr*)&myaddr, sizeof(myaddr)) < 0)ErrExit("bind");while (1) {recvfrom(fd, buf, BUFSIZ, 0, (Addr*)&peeraddr, &peerlen);printf("[%s:%d]%s\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);}return 0;
}