1. 程式人生 > >組播 IP_MULTICAST_LOOP迴環在Linux和Windows的差異

組播 IP_MULTICAST_LOOP迴環在Linux和Windows的差異

在TX2嵌入式開發板上(Ubuntu作業系統)編寫網路組播發送接收程式,首先了解一下組播.

linux多播程式設計

linux多播程式設計步驟:

1>建立一個socket;

2>設定多播的引數,例如超時時間TTL,本地迴環許可LOOP等

3>加入多播組

的4>傳送和接收資料

5>從多播組離開

多播程式設計使用setsockopt()函式和getsockopt()函式來實現,組播的選項是IP層的。

getsockopt()/setsockopt()

的選項

含    義

IP_MULTICAST_TTL

設定多播組資料的TTL值

IP_ADD_MEMBERSHIP

在指定介面上加入組播組

IP_DROP_MEMBERSHIP

退出組播組

IP_MULTICAST_IF

獲取預設介面或設定介面

IP_MULTICAST_LOOP

禁止組播資料回送

1.選項IP_MULTICASE_TTL

選項IP_MULTICAST_TTL允許設定超時TTL,範圍為0~255之間的任何值,例如:

unsigned char ttl=255;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl)); 

2.選項IP_MULTICAST_IF

選項IP_MULTICAST_IF用於設定組播的預設預設網路介面,會從給定的網路介面傳送,另一個網路介面會忽略此資料。例如:

struct in_addr addr;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr));

引數addr是希望多播輸出介面的IP地址,使用INADDR_ANY地址回送到預設介面。

預設情況下,當本機發送組播資料到某個網路介面時,在IP層,資料會回送到本地的迴環介面,選項IP_MULTICAST_LOOP用於控制資料是否回送到本地的迴環介面。例如:

unsigned char loop;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));引數loop設定為0禁止回送,設定為1允許回送。

 

3.選項IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP

加入或者退出一個多播組,通過選項IP_ADD_MEMBERSHIP和IP_DROP_MEMBER- SHIP,對一個結構struct ip_mreq型別的變數進行控制,struct ip_mreq原型如下:

struct ip_mreq          

    struct in_addr imn_multiaddr;      /*加入或者退出的廣播組IP地址*/ 

  struct in_addr imr_interface;      /*加入或者退出的網路介面IP地址*/

};

 

選項IP_ADD_MEMBERSHIP用於加入某個多播組,之後就可以向這個多播組傳送資料或者從多播組接收資料。此選項的值為mreq結構,成員imn_multiaddr是需要加入的多播組IP地址,成員imr_interface是本機需要加入廣播組的網路介面IP地址。例如:

struct ip_mreq mreq;

setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

 

但是實際測試使用過程中,有時候傳送方不需要接收自己傳送出去的資訊,所以使用IP_MULTICAST_LOOP,但是沒有工作,網路上搜索發現很多人都遇到了相同的問題,眾說紛紜,有的說傳送和接收使用相同的socket,發現下面這種說法更加靠譜.

Note  The Winsock version of the IP_MULTICAST_LOOP option is semantically different than the UNIX version of the IP_MULTICAST_LOOP option:

    In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
    In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path.

For example, applications ON and OFF (which are easier to track than X and Y) join the same group on the same interface; application ON sets the IP_MULTICAST_LOOP option on, application OFF sets the IP_MULTICAST_LOOP option off. If ON and OFF are Winsock applications, OFF can send to ON, but ON cannot sent to OFF. In contrast, if ON and OFF are UNIX applications, ON can send to OFF, but OFF cannot send to ON.

 

在windows平臺,  IP_MULTICAST_LOOP 應用到接收端.在接收端啟用IP_MULTICAST_LOOP. loop設定為1,表示接收自身傳送出去的資料,設定為0表示不接收
在Linux平臺,  IP_MULTICAST_LOOP 應用到傳送端.下面是實際的部分測試程式碼

	int ret  = -1;
	int loop = 1;
	struct timeval timeout = {1,0};
	
	client_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(client_fd == -1)
	{
		Log_error("sock error \n");
		return -1;
	}
	/*��ʼ����ַ*/
	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	local_addr.sin_port = htons(iPort);
	/*��socket*/
	ret=bind(client_fd,(struct sockaddr*)&local_addr,sizeof(local_addr));
	if(ret < 0)
	{
		close(client_fd);
		client_fd = -1;
		Log_error("bind error \n");
		return -2;
	}

	ret=setsockopt(client_fd,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
	if(ret < 0)
	{
		close(client_fd);
		client_fd = -1;
		Log_error("set sock error \n");
		return -3;
	}
	m_mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR);//�㲥��ַ
	m_mreq.imr_interface.s_addr = htonl(INADDR_ANY); //����ӿ�ΪĬ��?
	/*���������㲥��*/
	ret = setsockopt(client_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&m_mreq,sizeof(m_mreq));
	if(ret < 0)
	{
		close(client_fd);
		client_fd = -1;
		Log_error("set sock error \n");
		return -4;
	}

	setsockopt(client_fd,SOL_SOCKET,SO_RCVTIMEO, (char *)&timeout,sizeof(struct timeval));

	 //�����߳�
	g_thrUDPReadHdl.iInterval = iInterval;
	int iRet = 0;
	iRet = iPthreadCreate(&g_thrUDPReadHdl,
	                      vpMCProcThread,
	                      PTHREAD_PRI_MAX,
	                      TSK_STACK_SIZE,
	                      &g_thrUDPReadHdl);
	if (0 != iRet)
	{
	    Log_error("Create UDP data thread failed.\n");
	    close(client_fd);
		client_fd = -1;
		return -1;
	}