LWIP Sokect UDP组播

 

1 Socket编程-udp服务端和客户端通信

(1).建立一个套接字(Socket)

(2).绑定服务器端IP地址及端口号--服务器端

(3).通过SendTo()方法向指定主机发送消息

  (需提供主机IP地址及端口)

(4).通过ReciveFrom()方法接收指定主机发送的消息

 

2 UDP信息传递的方式分三类

①  单播Unicast:是客户端与服务器之间的点到点连接。

②  广播BroadCast:主机之间“一对所有”的通讯模式,广播者可以向网络中所有主机发送信息。广播禁止在Internet宽带网上传输(广播风暴)。

③  多播MultiCast:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据。

这里需要注意的是:只有UDP才有广播、组播的传递方式;而TCP是一对一连接通信。多播的重点是高效的把同一个包尽可能多的发送到不同的,甚至可能是未知的设备。但是TCP连接是一对一明确的,只能单播。

 

3 配置LWIP

3.1 打开lwipopts.h中IGMP组播功能

 

    #define LWIP_IGMP                   1

3.2 将以太网驱动stm32_eth.c中的void ETH_StructInit(ETH_InitTypeDef *ETH_InitStruct)函数中进行如下设置。

   

    ETH_InitStruct->ETH_ReceiveAll = ETH_ReceiveAll_Enable;//全部接收
    ETH_InitStruct->ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_None; //不多播帧过滤

3.3 修改在ethernetif.clow_level_init函数添加NETIF_FLAG_IGMP

#if LWIP_IGMP
	/* igmp support */
	netif->flags |= NETIF_FLAG_IGMP;
#endif

 

4 编写组播实现代码

UDP组播的基本步骤

  1. 建立socket
  2. socket和端口绑定
  3. 加入一个组播组
  4. 通过sendto / recvfrom进行数据的收发
  5. 关闭socket 

    服务器和客户端必须都要加入相同的组播地址才可以。

#define MCAST_ADDR         "233.0.0.6"
#define LOCAL_ADDR         "192.168.2.198"
#define MCAST_PORT         9090
#define MCAST_CLIENT_PORT  8080

void MulticastClient()
{
	int sock = -1;
	struct sockaddr_in local_addr, remote_addr;
	int recv_data_len;
	char* recv_data;
	socklen_t addrlen;
	int err = -1;
	char sendline[1024];
	while(1)
	{
		recv_data = (char *)rt_malloc(1024);
		if(recv_data == NULL)
		{
			printf("No memory\r\n");
			//return;
			goto __exit;
		}
		sock = socket(AF_INET, SOCK_DGRAM, 0);
		if(sock <0)
		{
			printf("UDP Socket error\r\n");
			goto __exit;
		}
		memset(&local_addr, 0 , sizeof(local_addr));
		local_addr.sin_family = AF_INET;
		local_addr.sin_port = htons(MCAST_PORT);
		#if 1
	  local_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
		#else
		local_addr.sin_addr.s_addr = inet_addr(LOCAL_ADDR); 
		#endif

		#if 1
		err = bind(sock, (struct sockaddr*)&local_addr, sizeof(local_addr));
		if(err<0)
		{
			printf("bind error\r\n");
			goto __exit;
		}
		struct ip_mreq mreq;
		mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR);
		#if 0
		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
		#else
		mreq.imr_interface.s_addr = inet_addr(LOCAL_ADDR);
		#endif
		err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
		if(err < 0)
		{
			printf("2 setsockopt():IP_ADD_MEMBERSHIP error\r\n");
			goto __exit;
		}
		#endif
		while(1)
		{
      memset(recv_data, 0, RECV_DATA);
			recv_data_len = recvfrom(sock, recv_data, RECV_DATA, 0, (struct sockaddr*)&remote_addr, &addrlen);
		  printf("receive from UDP server:%s\r\n", inet_ntoa(remote_addr.sin_addr));
			printf("recevie:%s\r\n", recv_data);	
			
			sprintf(sendline, "hello world\r\n");
			int send_length = 0;
			send_length = sendto(sock, sendline, sizeof("hello server!\r\n"), 0, 
						(struct sockaddr*)&remote_addr, sizeof(remote_addr));
			rt_thread_delay(100);
			if(send_length < 0)
			{
				printf("sendto() error!\r\n");
			}
			else
			{
				printf("sendto() ok %d!\r\n", send_length);
			}
		}
		
		__exit:
		if(sock >= 0) closesocket(sock);
		if(recv_data) rt_free(recv_data);
	}
   
}

5 测试工具和测试结果

 

参考链接:UDP之多播/组播

                  udp组播通信实现(c++)

                  UDP 组播---基本概念

                  关于UDP 中的组播问题

                 SOCKET UDP组播 实例(亲测可行)

                 UDP协议 sendto 和 recvfrom 浅析与示例

                  简介setsockopt和udp的多播(组播)广播

                   stm32f207实现组播

               

                   

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章