在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;
	}