文章链接:https://codemouse.online/archives/2020-03-01-235956
UDP应用
-
UDP的点对点通信
路由器是不转发广播包的
交换机会转发广播数据包
-
UDP广播数据包
广播只能在一个广播域(局域网)中传播,而不能跨网段传播
-
组播数据包
能够在组播组中进行传播的,并且路由器可以进行组播数据转发
-
如何识别广播包
MAC: 目的MAC是ff:ff:ff:ff:ff:ff
IP: 10.0.0.0/8 ----> 10.255.255.255这个网段
192.168.0.1/24 ---->192.168.0.255这个网段
设置UDP
-
对socket进行设置(组播,广播…)
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
-
通过tcpdump语句,抓包
tcpdump -i eth0 -w ./xxx.pacp
一个简单的udp-Demo点对点
-
服务端
// 创建sock int sock = socket(AF_INET, SOCK_DGRAM, 0); // 初始化对端地址信息 struct sockaddr_in s_addr; s_addr.sin_family = AF_INET; s_addr.sin_port = htons(7838); s_addr.sin_addr.s_addr = INADDR_ANY; int addr_len; // 绑定 bind(sock, (struct sockaddr *) &s_addr, sizeof(s_addr)); // 接收 char buff[128]; struct sockaddr_in c_addr; addr_len = sizeof(c_addr); recvfrom(sock, buff, sizeof(buff) - 1, 0,(struct sockaddr *) &c_addr, &addr_len); printf("recive come from %s:%d message:%s\n\r", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port), buff);
-
客户端:
// 创建sock int sock = socket(AF_INET, SOCK_DGRAM, 0); // 初始化对端地址信息 struct sockaddr_in s_addr; s_addr.sin_family = AF_INET; s_addr.sin_port = htons(7838); s_addr.sin_addr.s_addr = inet_addr(argv[1]); // 发送 int addr_len; char *buff = "i am here"; sendto(sock, buff, strlen(buff), 0,(struct sockaddr *) &s_addr, addr_len);
通过udp实现一个广播
-
服务器如上,没有什么区别
-
客户端:在普通udp基础上添加一个广播包设置
// 创建sock int sock = socket(AF_INET, SOCK_DGRAM, 0); // 初始化对端地址信息 struct sockaddr_in s_addr; s_addr.sin_family = AF_INET; s_addr.sin_port = htons(7838); s_addr.sin_addr.s_addr = inet_addr(argv[1]); // 设置为广播包 int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); // 发送 int addr_len; char *buff = "i am here"; sendto(sock, buff, strlen(buff), 0,(struct sockaddr *) &s_addr, addr_len);
通过udp实现组播
-
解析域名得到的hostent结构体
#include <netdb.h> struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ }
-
服务端:解析域名写法
struct sockaddr_in peeraddr; struct in_addr ia; unsigned int socklen; struct hostent *group; struct ip_mreq mreq; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&mreq, sizeof(struct ip_mreq)); // 解析域名 if (argv[1]) { if ((group = gethostbyname(argv[1])) == (struct hostent *) 0) { perror("gethostbyname"); exit(EXIT_FAILURE); } } else { printf("you should give me a group address, 224.0.0.0-239.255.255.255\n"); exit(EXIT_FAILURE); } // 获取到组播地址 bcopy((void *) group->h_addr, (void *) &ia, group->h_length); bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); // 设置入口地址 if (argv[2]) { // inet_pton 转换ip为二进制 if (inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0) { printf("Wrong dest IP address!\n"); exit(EXIT_FAILURE); } } else mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 设置组播,将自己的的地址加入到组播中 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(struct ip_mreq)) == -1) { perror("setsockopt"); exit(EXIT_FAILURE); } // 绑定自己的地址 socklen = sizeof(struct sockaddr_in); memset(&peeraddr, 0, socklen); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(7838); bcopy((void *) group->h_addr, (void *) &peeraddr.sin_addr, group->h_length); if (bind(sockfd, (struct sockaddr *) &peeraddr,sizeof(struct sockaddr_in)) == -1) { printf("Bind error\n"); exit(EXIT_FAILURE); } // 获取对端信息 #define BUFFLEN 1024 while(1) { char recmsg[BUFLEN+1] = {0}; socklen_t addrLen = sizeof(struct sockaddr); printf("ready 2 recv\n"); int recvRet = recvfrom(sockfd, recmsg, BUFLEN, 0,(struct sockaddr *) &peeraddr, &socklen); if (-1 == recvRet) { perror("recvfrom fail\n"); break; } printf("recvfrom recmsg is %s\n",recmsg); }
-
服务器:直接利用地址写法
int sockfd = socket(AF_INET,SOCK_DGRAM,0); if (-1 == sockfd) { perror("socket fail\n"); return -3; } printf("socket succ\n"); struct ip_mreq mreq; memset(&mreq,0,sizeof(struct ip_mreq)); mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 设置组播地址 mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); // 将设定的地址绑定到组播中 int setoptret = setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq)); if (-1 == setoptret) { perror("setsockopt fail\n"); return -4; } unsigned int socklen; struct sockaddr_in peeraddr; memset(&peeraddr,0,sizeof(struct sockaddr_in)); peeraddr.sin_family = AF_INET; peeraddr.sin_addr.s_addr = inet_addr(argv[2]); peeraddr.sin_port = htons(7838); if (-1 == bind(sockfd,(struct sockaddr *)(&peeraddr),sizeof(struct sockaddr))) { perror("bind fail\n"); return -5; } #define BUFFLEN 1024 while(1) { char recmsg[BUFLEN+1] = {0}; printf("ready 2 recv\n"); int recvRet = recvfrom(sockfd, recmsg, BUFLEN, 0,(struct sockaddr *) &peeraddr, &socklen); if (-1 == recvRet) { perror("recvfrom fail\n"); break; } printf("recvfrom recmsg is %s\n",recmsg); }
-
客户端
#deine BUFLEN 1024 struct sockaddr_in peeraddr, myaddr; char recmsg[BUFLEN + 1]; unsigned int socklen; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { printf("socket creating error\n"); exit(EXIT_FAILURE); } // 先设置组播地址,和端口 socklen = sizeof(struct sockaddr_in); memset(&peeraddr, 0, socklen); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(7838); //peeraddr.sin_addr.s_addr = inet_addr(argv[1]); if (argv[1]) { if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) { printf("wrong group address!\n"); exit(EXIT_FAILURE); } } else { printf("no group address!\n"); exit(EXIT_FAILURE); } // 设置自己的地址,等待接受 memset(&myaddr, 0, socklen); myaddr.sin_family = AF_INET; myaddr.sin_port = htons(23456); //myaddr.sin_addr.s_addr = inet_addr(argv[2]); if (argv[2]) { if (inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0) { printf("self ip address error!\n"); exit(EXIT_FAILURE); } } else myaddr.sin_addr.s_addr = INADDR_ANY; // 绑定自己的地址 if (bind(sockfd, (struct sockaddr *) &myaddr,sizeof(struct sockaddr_in)) == -1) { printf("Bind error\n"); exit(EXIT_FAILURE); } for (;;) { bzero(recmsg, BUFLEN + 1); printf("input message to send:"); if (fgets(recmsg, BUFLEN, stdin) == (char *) EOF) exit(EXIT_FAILURE);; if (sendto(sockfd, recmsg, strlen(recmsg), 0,(struct sockaddr *) &peeraddr, sizeof(struct sockaddr_in)) < 0) { printf("sendto error!\n"); exit(EXIT_FAILURE);; } printf("sned message:%s", recmsg); }