Linux下的TCP/IP编程----多播和广播的实现
2016-06-05 13:54
573 查看
在前边我们实现的都是服务端客户端这样点对点的通讯,数据只是从一个点到另一个点,但是当我们需要将一份数据同时发给指定的多个人时就遇到了问题,总不能建立多个TCP的长连接或者是多个UDP数据报吧。这时我们就应该考虑使用多播或者时广播来实现我们的需要。
多播的特点:
1. 多播服务端针对特定多播地址只发送一次数据
2. 即使只发送一次数据,但是组内的所有客户端都能收到数据
3. 多播组数可以在IP地址范围内任意增加
4. 加入特定的多播组即可接收发往该多播组的数据
多播的实现:
多播其实也是依赖于UDP方式,只是由之前的UDP点对点发送变成了一对多的发送,而这些改变主要依赖于我们对于socket可选项的设置。可以翻看之前对于socket可选项的介绍。Linux下的TCP/IP编程—-socket的可选项
最大生存时间(TTL):Time To Live的简称,是决定数据包传输距离的主要因素,其值用正数表示(不能大于十进制的255),并且每经过一个路由器值便减1,当TTL值为0时路由器便会丢弃这个数据包。
这样一个多播的发送者和接收者就编写完成了,其实在实际使用中并不会很明确的区分发送者和接受者。
主机之间一对所有的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),但是被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。广播分为直接广播和本地广播。
广播的特点:
1. 可以向广播域内的所有主机发送数据
2. 不能够跨越不同的网络,被路由器所隔离开。
广播和多播的区别:最主要的区别在于多播可以跨越网络,不受路由器隔离的影响,只要加入多播组就可以接收到数据。而广播只能是在广播域内传输,被路由器所隔离,防止形成广播风暴。
广播的实现:
广播也是基于UDP实现的,我们同样需要对socket的可选项进行设置。
直接广播:目的广播域之外的主机向广播域发送的广播,IP地址除了网络位之外,主机位都为1。例如向网络地址为192.168.10这个网段发送广播,则IP地址为192.168.10.255
本地广播:本地广播使用的IP地址限制为255.255.255.255,是广播域内的主机向该广播域发送广播时使用的IP地址。例如192.168.10.1这个主机想向本网段内所有主机发送广播,则要发送数据的目的IP地址为192.168.10.255
至此socket的多播和广播就完成了,其实都是在UDP的基础上进行的。主要对创建的默认的socket进行相应的设置,使得在发送UDP数据包时不再是点对点的,而是点对多的发送。
多播:
IP多播(也称多址广播或 组播)技术,是一种允许一台或多台主机(多播源)发送单一 数据包到多台主机(一次的,同时的)的TCP/ IP网络技术。多播作为一点对多点的通信,是节省 网络带宽的有效方法之一。多播组是D类IP地址(224.0.0.0~239.255.255.255)。多播的特点:
1. 多播服务端针对特定多播地址只发送一次数据
2. 即使只发送一次数据,但是组内的所有客户端都能收到数据
3. 多播组数可以在IP地址范围内任意增加
4. 加入特定的多播组即可接收发往该多播组的数据
多播的实现:
多播其实也是依赖于UDP方式,只是由之前的UDP点对点发送变成了一对多的发送,而这些改变主要依赖于我们对于socket可选项的设置。可以翻看之前对于socket可选项的介绍。Linux下的TCP/IP编程—-socket的可选项
多播Sender的实现:
在实现多播的Sender时我们只需要将UDP发送数据时的IP地址设置为多播组的IP地址,并为多播数据报设置最大存活时间(TTL)即可。最大生存时间(TTL):Time To Live的简称,是决定数据包传输距离的主要因素,其值用正数表示(不能大于十进制的255),并且每经过一个路由器值便减1,当TTL值为0时路由器便会丢弃这个数据包。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define TTL 64 #define BUFF_SIZE 30 void error_handling(char *message); int main(int argc, char *argv[]){ //声明发送者的socket int send_socket; //声明多波的地址 struct sockaddr_in multicast_addr; //数据包的最大生存时间 int live_time = TTL; //文件指针 FILE *fp; //字符缓冲 char buff[BUFF_SIZE]; if(argc != 3){ printf("Uasge : %s <GroupIP> <PORT> \n" ,argv[0]); exit(1); } //初始化socket,设置为多播组的IP地址和端口号 send_socket = socket(PF_INET,SOCK_DGRAM,0); memset(&multicast_addr,0,sizeof(multicast_addr)); multicast_addr.sin_family = AF_INET; //和之前的UDP设置方式一样,只是输入的是多播组的IP地址和端口号 multicast_addr.sin_addr.s_addr = inet_addr(argv[1]); multicast_addr.sin_port = htons(atoi(argv[2])); //为多播数据报设置最大生存时间 setsockopt(send_socket,IPPROTO_IP,IP_MULTICAST_TTL,(void *)&live_time,sizeof(live_time)); //打开文件 if((fp = fopen("test.txt","r")) == NULL){ error_handling("fopen() error"); } while(!(feof(fp))){ //从文件中读取数据 fgets(buff,BUFF_SIZE,fp); printf("%s",buff); //将数据发送到多播组 sendto(send_socket,buff,BUFF_SIZE,0,(struct sockaddr *) &multicast_addr,sizeof(multicast_addr)); sleep(2); } fclose(fp); close(send_socket); return 0; } void error_handling(char * message){ fputs(message,stderr); fputc('\n',stderr); exit(1); }
多播Receiver的实现:
多播的Receiver实现比Sender稍微复杂一点,在Receiver中多了一步声明加入多播组的步骤。#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define TTL 64 #define BUFF_SIZE 30 void error_handling(char *message); int main(int argc ,char *argv[]){ //声明接收者的 int receiver_socket; //每次读到的字符串长度 int str_len; //用于保存数据的字符缓冲 char * buff[BUFF_SIZE]; //receiver的地址 struct sockaddr_in receiver_addr; //声明一个用于多播的地址结构体 struct ip_mreq join_addr; if(argc!= 3){ printf("Uasge : %s <GroupIP> <PORT> ",argv[0]); exit(1); } //初始化receiver_socket receiver_socket = socket(PF_INET,SOCK_DGRAM,0); memset(&receiver_addr,0,sizeof(receiver_addr)); receiver_addr.sin_family = AF_INET; receiver_addr.sin_addr.s_addr = htonl(INADDR_ANY); receiver_addr.sin_port = htons(atoi(argv[2])); //绑定地址 if(bind(receiver_socket,(struct sockaddr *)&receiver_addr,sizeof(receiver_addr)) == -1){ error_handling("bind() error"); } //初始化多播地址组 join_addr.imr_multiaddr.s_addr = inet_addr(argv[1]);//要加入的多播组地址 join_addr.imr_interface.s_addr = htonl(INADDR_ANY);//加入该组的套接字所属的主机IP地址 //设置socket中的IP_ADD_MEMBERSHIP选项加入多播组 setsockopt(receiver_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void *)&join_addr,sizeof(join_addr)); while(1){ //接收发送来的消息,因为之前已经将socket注册到组播中 str_len = recvfrom(receiver_socket,buff,BUFF_SIZE-1,0,NULL,0); if(str_len<0){ break; } buff[str_len] = 0; //使用标准的输入流输出接受到的数据 fputs(buff,stdout); } close(receiver_socket); return 0; } void error_handling(char * message){ fputs(message,stderr); fputc('\n',stderr); exit(1); }
这样一个多播的发送者和接收者就编写完成了,其实在实际使用中并不会很明确的区分发送者和接受者。
广播:
多播可以很便捷的使我们同时向多个地址发送数据,但前提是要加入对应的多播组,否则就无法接受数据。但是有时我们需要将数据发送给所有的人(例如发通告这一行为),这时多播也无法便捷的实现这个需求(因为要求所有的人都加入多播组),我们就要考虑使用广播来实现这个功能。主机之间一对所有的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),但是被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。广播分为直接广播和本地广播。
广播的特点:
1. 可以向广播域内的所有主机发送数据
2. 不能够跨越不同的网络,被路由器所隔离开。
广播和多播的区别:最主要的区别在于多播可以跨越网络,不受路由器隔离的影响,只要加入多播组就可以接收到数据。而广播只能是在广播域内传输,被路由器所隔离,防止形成广播风暴。
广播的实现:
广播也是基于UDP实现的,我们同样需要对socket的可选项进行设置。
广播Sender的实现:
广播也是基于UDP的,根据其使用时的IP地址可以分为两类:直接广播:目的广播域之外的主机向广播域发送的广播,IP地址除了网络位之外,主机位都为1。例如向网络地址为192.168.10这个网段发送广播,则IP地址为192.168.10.255
本地广播:本地广播使用的IP地址限制为255.255.255.255,是广播域内的主机向该广播域发送广播时使用的IP地址。例如192.168.10.1这个主机想向本网段内所有主机发送广播,则要发送数据的目的IP地址为192.168.10.255
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define TTL 64 #define BUFF_SIZE 30 void error_handling(char *message); int main(int argc,char *argv[]){ //sender的socket int sender_socket; //广播地址 struct sockaddr_in broadcast_addr; //文件指针 FILE *fp; //字符缓冲 char buff[BUFF_SIZE]; //用于配置socket参数 int opt_so_broadcast= 1; if(argc != 3){ printf("Uasge : %s <GroupIP> <PORT> \n" ,argv[0]); exit(1); } //初始化socket sender_socket = socket(PF_INET,SOCK_DGRAM,0); memset(&broadcast_addr,0,sizeof(broadcast_addr)); broadcast_addr.sin_family = AF_INET; broadcast_addr.sin_addr.s_addr = inet_addr(argv[1]); broadcast_addr.sin_port = htons(atoi(argv[2])); //设置socket可选项,因为默认生成的会阻止广播,所以要将可选项中的SO_BROADCAST标志置为1 setsockopt(sender_socket,SOL_SOCKET,SO_BROADCAST,(void *)&opt_so_broadcast,sizeof(opt_so_broadcast)); //打开文件 if((fp = fopen("word_file.txt","r")) == NULL){ error_handling("fopen() error"); } while(!(feof(fp))){ //从文件中读取数据 fgets(buff,BUFF_SIZE,fp); printf("%s",buff); //将数据发送到多播组 sendto(sender_socket,buff,strlen(buff),0,(struct sockaddr *) &broadcast_addr,sizeof(broadcast_addr)); sleep(2); } fclose(fp); close(sender_socket); return 0; } void error_handling(char * message){ fputs(message,stderr); fputc('\n',stderr); exit(1); }
广播Receiver的实现:
广播的Receiver和UDP的并没有太大的区别,主要是在接受的时候使用的是recvfrom()函数#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define TTL 64 #define BUFF_SIZE 30 void error_handling(char * message); int main(int argc , char *argv[]){ int receiver_socket; struct sockaddr_in receiver_addr; int str_len; char buff[BUFF_SIZE]; if(argc!= 2){ printf("Uasge : %s <GroupIP> <PORT> ",argv[0]); exit(1); } //初始化receiver_socket receiver_socket = socket(PF_INET,SOCK_DGRAM,0); memset(&receiver_addr,0,sizeof(receiver_addr)); receiver_addr.sin_family = AF_INET; receiver_addr.sin_addr.s_addr = htonl(INADDR_ANY); receiver_addr.sin_port = htons(atoi(argv[1])); //绑定地址 if(bind(receiver_socket,(struct sockaddr *)&receiver_addr,sizeof(receiver_addr)) == -1){ error_handling("bind() error"); } while(1){ str_len = recvfrom(receiver_socket,buff,BUFF_SIZE-1,0,NULL,0); if(str_len < 0){ break; } buff[BUFF_SIZE] = 0; fputs(buff,stdout); } close(receiver_socket); return 0; } void error_handling(char * message){ fputs(message,stderr); fputc('\n',stderr); exit(1); }
至此socket的多播和广播就完成了,其实都是在UDP的基础上进行的。主要对创建的默认的socket进行相应的设置,使得在发送UDP数据包时不再是点对点的,而是点对多的发送。
相关文章推荐
- Linux socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- Linux 下无损图片压缩小工具介绍