请问AT设备,支持通过SAL使用组播功能吗?逛了一圈论坛实现好像底层都是lwip的。
使用esp8266模块,setsockopt时报错显示不支持操作,看了一下好像是atsocket没实现相关操作?
日志如下所示
msh />bing_test esp0
socket bind network interface device(esp0) success!
[E/at.skt] AT socket (0) not support option level : 0.
setsockopt failed !
msh />
测试代码如下:
#include <rtthread.h>
#include <arpa/inet.h>
#include <netdev.h>
#define SERVER_PORT 8888
static int bing_test(int argc, char **argv)
{
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
struct netdev *netdev = RT_NULL;
int sockfd = -1;
if (argc != 2)
{
rt_kprintf("bind_test [netdev_name] --bind network interface device by name.\n");
return -RT_ERROR;
}
/* 通过名称获取 netdev 网卡对象 */
netdev = netdev_get_by_name(argv[1]);
if (netdev == RT_NULL)
{
rt_kprintf("get network interface device(%s) failed.\n", argv[1]);
return -RT_ERROR;
}
// 多播 IP 地址
char muticast_addr[16] = "239.255.0.1";
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
rt_kprintf("Socket create failed.\n");
return -RT_ERROR;
}
/* 初始化需要绑定的客户端地址 */
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(SERVER_PORT);//change
/* 获取网卡对象中 IP 地址信息 */
client_addr.sin_addr.s_addr = netdev->ip_addr.addr;
rt_memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));
if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0)
{
rt_kprintf("socket bind failed.\n");
closesocket(sockfd);
return -RT_ERROR;
}
rt_kprintf("socket bind network interface device(%s) success!\n", netdev->name);
// 多播地址结构体
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr(muticast_addr); /*<! 多播组 IP 地址设置 */
mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*<! 待加入多播组的 IP 地址 */
// 添加多播组成员(该语句之前,socket 只与 某单播IP地址相关联 执行该语句后 将与多播地址相关联)
int ret = setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
if(ret < 0)
{
rt_kprintf("setsockopt failed !");
return;
}
else
{
rt_kprintf("setsockopt success\n");
}
char buf[1024];
int length=0;
struct sockaddr_in sender;
int sender_len=sizeof(sender);
while(1)
{
memset(buf, 0, sizeof(buf));
length = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&sender,(socklen_t *)&sender_len);
buf[length]='\0';
rt_kprintf("%s %d : %s\n", inet_ntoa(sender.sin_addr), ntohs(sender.sin_port), buf);
}
setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
closesocket(sockfd);
return RT_EOK;
}
#ifdef FINSH_USING_MSH
#include <finsh.h>
MSH_CMD_EXPORT(bing_test, bind network interface device test);
#endif /* FINSH_USING_MSH */
at
int at_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)
{
struct at_socket *sock;
int32_t timeout;
if (optval == RT_NULL || optlen == RT_NULL)
{
LOG_E("AT getsocketopt input option value or option length error!");
return -1;
}
sock = at_get_socket(socket);
if (sock == RT_NULL)
{
return -1;
}
switch (level)
{
case SOL_SOCKET:
switch (optname)
{
case SO_RCVTIMEO:
timeout = sock->recv_timeout;
((struct timeval *)(optval))->tv_sec = (timeout) / 1000U;
((struct timeval *)(optval))->tv_usec = (timeout % 1000U) * 1000U;
break;
case SO_SNDTIMEO:
timeout = sock->send_timeout;
((struct timeval *) optval)->tv_sec = timeout / 1000U;
((struct timeval *) optval)->tv_usec = (timeout % 1000U) * 1000U;
break;
default:
LOG_E("AT socket (%d) not support option name : %d.", socket, optname);
return -1;
}
break;
default:
LOG_E("AT socket (%d) not support option level : %d.", socket, level);
return -1;
}
return 0;
}