Linux网络编程——广播、多播

广播和多播编程都是建立在UDP通信的基础上,通过setsockopt函数即可发送广播数据报或多播数据报。

 

int setsockopt(int fd,int level,int optname,const char*optval,int optlen)

参数:1、套接字描述符

   2、选项定义层次,可为SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP。在广播中使用SOL_SOCKET

   3、根据第二个参数,可为不同的值,在选定SOL_SOCKET的前提下,可为

    SO_BROADCAST:允许发送广播数据报

    SO_RCVBUF:接受缓冲区大小

    SO_SNDBUF:发送缓冲区大小

   4、第三个参数的长度

用于设置状态字的选项值设置。成功返回0,失败返回-1

广播:

接受方

 1 #include<iostream>
 2 #include<arpa/inet.h>
 3 #include<stdio.h>
 4 #include<string.h>
 5 #include<sys/socket.h>
 6 #include<sys/types.h>
 7 #include<netinet/in.h>
 8 #include<unistd.h>
 9 using namespace std;
10 
11 int main()
12 {
13     struct sockaddr_in addr,recvaddr;
14     socklen_t len=sizeof(recvaddr);
15     int sockfd,op;
16     char buf[512];
17 
18     sockfd=socket(AF_INET,SOCK_DGRAM,0);
19     if(sockfd<0)
20     {
21         cout<<"socket error"<<endl;
22         return -1;
23     }
24 
25     addr.sin_family=AF_INET;
26     addr.sin_port=htons(2501);
27     addr.sin_addr.s_addr=htons(INADDR_ANY);
28 
29     op=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
30     if(op<0)
31     {
32         cout<<"bind error"<<endl;
33         return -1;
34     }
35 
36     recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&recvaddr,&len);
37     cout<<"recv data from "<<ntohs(recvaddr.sin_port)<<" :"<<buf<<endl;
38 
39     //char buff[512]="1234567890987654321";
40     //sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&recvaddr,len);
41     return 0;
42 }

发送广播数据:

 1 #include<sys/socket.h>
 2 #include<sys/types.h>
 3 #include<iostream>
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<netinet/in.h>
 8 #include<arpa/inet.h>
 9 using namespace std;
10 
11 int main()
12 {
13     int sockfd;
14     int op;
15     struct sockaddr_in addr,saddr;
16     socklen_t len=sizeof(saddr);
17     int i,j;
18 
19     sockfd=socket(AF_INET,SOCK_DGRAM,0);
20     if(sockfd<0)
21     {
22         cout<<"socket error"<<endl;
23         return -1;
24     }
25 
26     addr.sin_family=AF_INET;
27     addr.sin_port=htons(2501);
28     addr.sin_addr.s_addr=htons(INADDR_ANY);
29 
30     int yes=1;
31     setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&yes,sizeof(yes));
32     char buff[512]="0987654321234567890";
33     sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&addr,sizeof(addr));
34     cout<<"send: "<<buff<<endl;
35 
36     return 0;
37 }

 

多播:

广播会向同一子网的主机发送消息,有时候会严重浪费网络带宽;而多播则只会向出于同一多播组的主机发送消息。

这里先说一下IPv4多播地址结构体:

struct in_addr

{

  in_addr_t   s_addr;

}

sturct ip_mreq

{

  struct in_addr imr_multiaddr;//多播组IP,类似QQ中的QQ群号,范围224.0.0.0到239.255.255.255其中224.0.0.0不可取

  struct in_addr imr_interface;//要加入多播组的IP

}

int setsockopt(int fd,int level,int optname,const char*optval,int optlen)

参数:1、套接字描述符

   2、选项定义层次,可为SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP。在多播中使用IPPROTO_IP

   3、根据第二个参数,可为不同的值,在选定IPPROTO_IP的前提下,可为

    IP_ADD_MEMBERSHIP:加入多播组

    IP_DROP_MEMBERSHIP:离开多播组

    IP_MULTICAST_LOOP:设置回环许可,即自己发送的多播数据会发送到本地回环接口

   4、第三个参数的长度

用于设置状态字的选项值设置。成功返回0,失败返回-1

广播:

接受方

 1 #include<sys/socket.h>
 2 #include<sys/types.h>
 3 #include<iostream>
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<netinet/in.h>
 8 #include<arpa/inet.h>
 9 #include<errno.h>
10 #include<unistd.h>
11 using namespace std;
12 
13 int main(int argc,char**argv)
14 {
15     int sockfd;
16     int op;
17     struct sockaddr_in addr,saddr;
18     socklen_t len=sizeof(saddr);
19     int i,j;
20 
21     sockfd=socket(AF_INET,SOCK_DGRAM,0);
22     if(sockfd<0)
23     {
24         cout<<"socket error"<<endl;
25         return -1;
26     }
27 
28     memset(&addr,0,sizeof(addr));
29     addr.sin_family=AF_INET;
30     addr.sin_port=htons(8000);//多播服务器端口,使用别的端口会返回errno=22
31     addr.sin_addr.s_addr=htonl(INADDR_ANY);
32     op=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
33     if(op<0)
34     {
35         cout<<"bind error"<<endl;
36         return 0;
37     }
38     
39     int yes=1;
40     op=setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_LOOP,&yes,sizeof(yes));//设置回环许可
41     if(op<0)
42     {
43         cout<<"set LOOP error"<<endl;
44         return 0;
45     }
46     struct ip_mreq mreq;
47     bzero(&mreq,sizeof(mreq));
48     mreq.imr_multiaddr.s_addr=inet_addr("224.0.0.88");
49     mreq.imr_interface.s_addr=htonl(INADDR_ANY);
50     
51     op=setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mreq,sizeof(mreq));
52     if(op<0)
53     {
54         cout<<errno<<endl;
55         return 0;
56     }
57     
58     char buff[512];
59     char recv_buff[512]="";
60     cout<<"111"<<endl;
61     for(i=1;i<=5;i++)
62     {
63         sleep(3);
64         memset(recv_buff,0,sizeof(recv_buff));
65         len=sizeof(addr);
66         recvfrom(sockfd,recv_buff,sizeof(recv_buff),0,(struct sockaddr*)&addr,&len);
67         cout<<"recv: "<<recv_buff<<endl;
68     }
69 
70     return 0;
71 }

发送方:

 1 #include<sys/socket.h>
 2 #include<sys/types.h>
 3 #include<iostream>
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<netinet/in.h>
 8 #include<arpa/inet.h>
 9 #include<errno.h>
10 #include<unistd.h>
11 using namespace std;
12 int main()
13 {
14     struct sockaddr_in addr;
15     socklen_t len;
16     int i,j;
17     int sockfd=socket(AF_INET,SOCK_DGRAM,0);
18     addr.sin_family=AF_INET;
19     addr.sin_port=htons(8000);//多播服务器端口
20     addr.sin_addr.s_addr=inet_addr("224.0.0.88");
21     
22     char buff[512]="123456789";
23     for(i=9;i<=14;i++)
24     {
25         sleep(3);
26         buff[i]=(i-8)+'0';
27         buff[i+1]=0;
28         len=sizeof(addr);
29         sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&addr,sizeof(addr));
30         cout<<"1111"<<endl;
31         
32     }
33     return 0;
34     
35 }

参考书籍——《Linux网络编程》

上一篇:网络编程:linux下的socket套接字编程之TCP服务器


下一篇:linux-TCP多线程的并发服务器- 以言责人甚易,以义持己实难!!!