linux 組播
1、Linux下組播 IGMP(Internet Group Managerment Protocol)---- Internet組管理協議,是因特網協議家族中的一個組播協議;
2、除了組播(又稱多播),還有單播和廣播;具體的定義和區別網上能百度到;
3、常用的組播地址如下:
224.0.1.0~238.255.255.255為使用者可用的組播地址(臨時組地址),全網範圍內有效。
239.0.0.0~239.255.255.255為本地管理組播地址,僅在特定的本地範圍內有效。
4、組播發送程式,server.c:
/*
*broadcast_server.c - 多播服務程式
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#define MCAST_PORT 8888
#define MCAST_ADDR "224.1.1.100" /*一個區域性連線多播地址,路由器不進行轉發*/
#define MCAST_DATA "Broadcast test data"
#define MCAST_INTERVAL 2 /*傳送間隔時間*/
int main(int argc, char*argv)
{
int s;
struct sockaddr_in mcast_addr;
s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (s == -1)
{
perror("socket()");
return -1;
}
memset(&mcast_addr, 0, sizeof(mcast_addr));
mcast_addr.sin_family = AF_INET; //型別
mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR); //IP地址
mcast_addr.sin_port = htons(MCAST_PORT); //埠
/*向多播地址傳送資料*/
while(1) {
int n = sendto(s, /*套接字描述符*/
MCAST_DATA, /*資料*/
sizeof(MCAST_DATA), /*長度*/
0,
(struct sockaddr*)&mcast_addr,
sizeof(mcast_addr)) ;
if( n < 0)
{
perror("sendto()");
return -2;
}
printf("send ...\n"); //***debug
sleep(MCAST_INTERVAL); /*等待一段時間*/
}
return 0;
}
5、組播接收段程式,client.c :
/*
多播客戶端在接收多播組的資料之前需要先加入多播組,當接收完畢後要退出多播組。*/
/*
*broadcast_client.c - 多播的客戶端
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#define MCAST_PORT 8888
#define MCAST_ADDR "224.1.1.100" /*一個區域性連線多播地址,路由器不進行轉發*/
#define MCAST_INTERVAL 2 /*傳送間隔時間*/
#define BUFF_SIZE 256 /*接收緩衝區大小*/
int main(int argc, char*argv[])
{
int s; /*套接字檔案描述符*/
struct sockaddr_in local_addr; /*本地地址*/
int err = -1;
s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (s == -1)
{
perror("socket()");
return -1;
}
/*初始化地址*/
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR); //如果使用預設的htonl(INADDR_ANY);也可以,如果網路中有多個組播組,這裡可以指定
local_addr.sin_port = htons(MCAST_PORT); // 組播伺服器的埠
/*繫結socket*/
err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ;
if(err < 0)
{
perror("bind()");
return -2;
}
/*設定迴環許可*/
int loop = 1;
err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop));
if(err < 0)
{
perror("setsockopt():IP_MULTICAST_LOOP");
return -3;
}
struct ip_mreq mreq; /*加入多播組*/
mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); /*多播地址*/
mreq.imr_interface.s_addr = inet_addr("192.168.1.251"); /*這裡可以是預設的介面htonl(INADDR_ANY); ,在多網絡卡時,可以選擇要加入組播組的網絡卡*/
/*將本機加入多播組*/
err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)); //將本機加入組播組
if (err < 0)
{
perror("setsockopt():IP_ADD_MEMBERSHIP");
return -4;
}
int times = 0;
int addr_len = 0;
char buff[BUFF_SIZE];
int n = 0;
/*迴圈接收多播組的訊息,100次後退出*/
for(times = 0;times<100;times++)
{
addr_len = sizeof(local_addr);
memset(buff, 0, BUFF_SIZE); /*清空接收緩衝區*/
/*接收資料*/
n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,&addr_len);
if( n== -1)
{
perror("recvfrom()");
}
printf("Recv %dst message from server: %s\n", times, buff);
sleep(MCAST_INTERVAL);
}
/*退出多播組*/
err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq)); //退出組播組
close(s);
return 0;
}
編譯:
gcc server.c -o server
gcc client.c -o client
6、server端如果沒有配置路由,請新增路由 route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
否則資料無法傳送到組播地址;
7、server和client可以在不同網段的PC上執行,如果client端收不到資料,請執行tcpdump看是否有收到組播資料,如果沒有,請檢查網線,如果有,但是client程式卻收不到資料(我的fedora18就出現了這個情況),這時可能是linux 反向過濾造成的;
在/etc/sysctl.conf下
把 net.ipv4.conf.all.rp_filter和 net.ipv4.conf.default.rp_filter設為0即可
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
reboot重啟即可;
8、client可以執行在多個PC裝置上以接收同一個server端的訊息;
9、但是如果一臺PC上有兩個網絡卡裝置eth0(192.168.0.251)和eth1(192.168.1.251),這兩個裝置不能同時執行client接收同一個組的資料,但是可以接收不同組的資料(比如eth0接收224.1.1.100組的訊息,eth1接收224.1.1.101組的訊息);
我理解的是一般也不需要這麼用,一個裝置上兩個網路裝置接收一樣的訊息也沒必要;