(1).建立一个套接字(Socket)
(2).绑定服务器端IP地址及端口号--服务器端
(3).通过SendTo()方法向指定主机发送消息
(需提供主机IP地址及端口)
(4).通过ReciveFrom()方法接收指定主机发送的消息
① 单播Unicast:是客户端与服务器之间的点到点连接。
② 广播BroadCast:主机之间“一对所有”的通讯模式,广播者可以向网络中所有主机发送信息。广播禁止在Internet宽带网上传输(广播风暴)。
③ 多播MultiCast:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据。
这里需要注意的是:只有UDP才有广播、组播的传递方式;而TCP是一对一连接通信。多播的重点是高效的把同一个包尽可能多的发送到不同的,甚至可能是未知的设备。但是TCP连接是一对一明确的,只能单播。
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.c
中low_level_init
函数添加NETIF_FLAG_IGMP
#if LWIP_IGMP
/* igmp support */
netif->flags |= NETIF_FLAG_IGMP;
#endif
服务器和客户端必须都要加入相同的组播地址才可以。
#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);
}
}
参考链接:UDP之多播/组播
udp组播通信实现(c++)
UDP 组播---基本概念
关于UDP 中的组播问题
SOCKET UDP组播 实例(亲测可行)
UDP协议 sendto 和 recvfrom 浅析与示例
简介setsockopt和udp的多播(组播)广播
stm32f207实现组播