大家好,欢迎来到IT知识分享网。
1 多播
&emsp 多播(Multicast )方式的数据传输是基于UDP完成的。 因此,与UDP服务器端/客户端的实现方式非常接近。 区别在于, UDP数据传输以单一目标进行,而多播数据同时传递到加入(注册)特定组的大量主机。 换言之,采用多播方式时,可以同时向多个主机传递数据。
1.1 多播的数据传输方式及流量方面的优点
多播的数据传输特点如下:
- 多播服务端针对特定多播组,只发送一次数据。
- 即使只发送一次数据,但该组内的所有客户端都会接收数据。
- 多播组数可在IP地址范围内任意增加。
- 加入特定组即可接收发往该多播的数据。
多播是D类IP地址(224.0.0.0~239.255.255.255),”加入多播组”可以理解为在D类IP地址中,我希望接收发往目标239.234.218.234的多播数据。
多播是基于UDP完成的,也就是说,多播数据包的格式与UDP数据包相同。不同的是,向网络发送一个多播数据包时,路由器将复制该数据包并传递到多个主机。多播需要借助路由器完成,如下图所示:
不要觉得频繁复制同一数据包,会不利于网络流量,因为不会向同一区域发送多个相同的数据包。相当于羊村的100之羊,从很远的地方定了一批相同的订单,使用TCP/UDP需要送100次,但是使用多播,只需要送一次到羊村门口,然后村里驿站复制100份然后给小羊就行。基于这种特性,多播主要用于“多媒体数据的实时传输”。
注意:虽然理论上可以完成多播通信,但不少路由器并不支持多播,或即便支持也因网络拥堵问题故意阻断多播。因此为了在不支持多播的路由器中完成多播通信,也会使用隧道技术。
1.2 路由和TTL,以及加入组的方法
int send_sock; int time_live = 64; ... send_sock = socket(PF_INET, SOCK_DGRAM, 0); setsockopt(send_sock, IPPROTO, IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live)); ...
另外,加入多播组也通过设置套接字选项完成,协议层为IPPROTO_IP
,选项为IP_ADD_MEMBERSHIP
。具体代码如下:
int recv_sock; struct ip_mreq join_adr; ... recv_sock = socket(FP_INET, SOCK_DGRAM, 0); ... join_adr.imr_multiaddr.saddr = "多播组地址信息"; join_adr.imr_interface.saddr = "加入多播组的主机地址信息"; setsockopt(recv_sock, IPPROTO, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));
ip_mreq
的结构体定义如下:
struct ip_mreq {
struct in_addr imr_multiaddr; struct in_addr imr_interface; }
1.3 实现多播Sender 和 Receiver
多播中使用“发送者”和“接收者”替代服务端和客户端,此处Sender是多播数据的发送主体,Receiver是多播数据的发送主体,Receiver需要加入多播组接收数据。下面给出示例,示例背景如下:
- Sender:向AAA组广播文件中保存的新闻消息
- Receiver:接收传递到AAA组的新闻信息
news_sender.c
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #define TTL 64 #define BUF_SIZE 30 void ErrorHandler(char* message) {
fputs(message, stderr); fputc('\n', stderr); exit(1); } int main(int argc, char* argv[]) {
int send_sock; struct sockaddr_in mul_adr; int time_live = TTL; FILE *fp; char buf[BUF_SIZE]; if (argc != 3) {
printf("Usage : %s <IP><PORT>\n", argv[0]); exit(1); } //多播通信基于UDP send_sock = socket(PF_INET, SOCK_DGRAM, 0); //设置传输数据的目标地址信息 memset(&mul_adr, 0, sizeof(mul_adr)); mul_adr.sin_family = AF_INET; mul_adr.sin_addr.s_addr = inet_addr(argv[1]); mul_adr.sin_port = htons(atoi(argv[2])); //设置TTL信息 setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live)); if (fp = fopen("news.txt", "r") == NULL) {
ErrorHandler("fopen() error"); } //实际传输数据的区域。 while (!feof(fp)) {
fgets(buf, BUF_SIZE, fp); sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&mul_adr, sizeof(mul_adr)); sleep(2); //纯纯添加时间间隔,没意义的 } fclose(fp); close(send_sock); return 0; }
news_receiver.c
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #define BUF_SIZE 30 void ErrorHandler(char* message) {
fputs(message, stderr); fputc('\n', stderr); exit(1); } int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage : %s <GroupIP><PORT> \n", argv[0]); exit(1); } int recv_sock; int str_len; char buf[BUF_SIZE]; struct sockaddr_in adr; struct ip_mreq join_adr; recv_sock = socket(PF_INET, SOCK_DGRAM, 0); memset(&adr, 0, sizeof(adr)); adr.sin_family = AF_INET; adr.sin_addr.s_addr = inet_addr(INADDR_ANY); adr.sin_port = htons(atoi(argv[2])); if (bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr)) == -1) {
ErrorHandler("bind error"); } //初始化结构体ip_mreq join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]); //初始化多播组地址 join_adr.imr_interface.s_addr = htonl(INADDR_ANY); //加入多播组 setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr)); while (1) {
//不知道传输数据的主机地址信息,所以传0 str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0); if (str_len < 0) {
break; } buf[str_len] = 0; fputs(buf, stdout); } close(recv_sock); return 0; }
2 广播
广播与多播都是一次性向多个主机发送数据,但是传输数据的范围有区别。多播即使在跨越不同网络的情况下,只要加入多播组就能接收数据。相反,广播只能向同一网络中的主机传输数据。
2.1 广播的理解及实现方法
广播是向同一网络中所有主机传输数据的方法。广播也是基于UDP完成的,根据传输数据时使用的IP地址的形式,广播分为如下2种。
- 直接广播
- 本地广播
int send_sock; int bcast = 1; .... send_sock = socket(PF_INET, SOCK_DGRAM, 0); .... setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&bcast, sizeof(bcast)); ....
2.2 实现广播数据的Sender 和 Receiver
new_sender_brd.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUFF_SIZE 30 void ErrorHandler(char* message) {
fputs(message, stderr); fputc('\n', stderr); exit(1); } int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage: %s <Boardcast IP> <PORT>\n", argv[0]); exit(1); } int send_sock = socket(PF_INET, SOCK_DGRAM, 0); struct sockaddr_in broad_addr; memset(&broad_addr, 0, sizeof(broad_addr)); broad_addr.sin_family = AF_INET; broad_addr.sin_addr.s_addr = inet_addr(argv[1]); broad_addr.sin_port = htons(atoi(argv[2])); int bcast = 1; setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&bcast, sizeof(bcast)); FILE* fp; if((fp = fopen("news.txt", "r")) == NULL) {
ErrorHandler("fopen() error"); } char buf[BUFF_SIZE]; while(!feof(fp)) {
fgets(buf, BUFF_SIZE, fp); sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&broad_addr, sizeof(broad_addr)); sleep(2); } close(send_sock); return 0; }
news_receiver_brd.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUFF_SIZE 30 void ErrorHandler(char* message) {
fputs(message, stderr); fputc('\n', stderr); exit(1); } int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage : %s <PORT> \n", argv[0]); exit(1); } int recv_sock; struct sockaddr_in adr; int str_len; char buf[BUFF_SIZE]; recv_sock = socket(PF_INET, SOCK_DGRAM, 0); memset(&adr, 0, sizeof(adr)); adr.sin_family = AF_INET; adr.sin_addr.s_addr = htonl(INADDR_ANY); adr.sin_port = htons(atoi(argv[1])); if (bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr)) == -1) {
ErrorHandler("bind error"); } while (1) {
str_len = recvfrom(recv_sock, buf, BUFF_SIZE-1, 0, NULL, 0); if (str_len < 0) {
break; } buf[str_len] = 0; fputs(buf, stdout); } close(recv_sock); return 0; } ```
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/125882.html