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實現組播

               

                   

 

 

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