- 我最近使用at socket ,at device 组件创建tcpclient,使用select函数实现,发现select只能监控一个socket fd,监控两个socket fd就不能正常接收数据。应用代码如下:
/**
* @brief tcp client mode task entry
*
* @param arg
*/
void net_tcpmode_task(void *arg)
{
fd_set rdset;
int r, ret;
int n;
char *buff_rd;
int write_sz;
int max_fd;
struct timeval tv;
int size = 0;
int heartcnt = 0, short_cnt = 0;
int socketfd,socketfd2;
int sum= 0;
start:
socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd < 0)
{
LOG_E("create socket fail");
goto start;
}
socketfd2 = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd2 < 0)
{
LOG_E("create socket fail");
goto start;
}
r = tcpclient_connect(socketfd,DEFAULT_TCPSERVER_ADDR,DEFAULT_TCPSERVER_PORT);
if(r < 0 )
{
rt_thread_mdelay(1000);
goto start;
}
r = tcpclient_connect(socketfd2,DEFAULT_TCPSERVER_ADDR,32502);
if(r < 0 )
{
rt_thread_mdelay(1000);
goto start;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
buff_rd = rt_malloc(1024);
if(buff_rd == NULL)
{
LOG_E("alloc buff_rd fail\r\n");
}
while(1)
{
FD_ZERO(&rdset);
FD_SET(socketfd, &rdset);
FD_SET(socketfd2, &rdset);
max_fd = (socketfd2 > socketfd)?socketfd2:socketfd;
r = select(max_fd + 1, &rdset, NULL, NULL, &tv);
if (r < 0)
{
LOG_E("select fail,restart");
break;
}
else if (r == 0)
{
ret = send(socketfd,"heart",5,MSG_DONTWAIT);
if(ret <= 0)
{
break;
}
sum = 0;
}
if (FD_ISSET(socketfd, &rdset)) //网络接收数据
{
ret = recv(socketfd,buff_rd,1024,0);
if(ret <= 0)
break;
LOG_I("fd %d rcv %d bytes",socketfd,ret);
}
if (FD_ISSET(socketfd2, &rdset)) //网络接收数据
{
ret = recv(socketfd2,buff_rd,1024,0);
if(ret <= 0)
break;
LOG_I("fd %d rcv %d bytes",socketfd2);
}
}
__end:
rt_free(buff_rd);
closesocket(socketfd);
closesocket(socketfd2);
rt_thread_mdelay(1000);
goto start;
}
2.于是我从select 函数的实现,poll,at_poll函数上寻找原因,终于在at_poll函数发现了问题,如下:

红色箭头是我改正后的,蓝色箭头是源码的,其实sal socket 的fd赋值是在file->vnode->data
里面,而不是file->data
,这个bug会导致select只能检测sal socket为0的标识符,因为file->data
一直是0,所以才出现我应用中的问题,如下,从net_sockets.c文件,我们可以看到file->vnode->data
的赋值,如下:

3.这个bug总共发去我两天时间去找,着实不好发现。