这几天在搞赛灵思公司的ZYNQ-7000芯片,使用了ALINX的开发板,想在此平台上跑petalinux,在此基础上进行linux开发。以前都是使用QT之类的封装库,在windows上开发,首次在linux环境下开发,然后想使用select来实现多路复用,不用每次接收socke数据就阻塞。 在此过程中发现select函数时灵时不灵。现象为如果客户端的发送周期小于我的select的timeout时间时可以接收到数据,但是timeout时间小于客户端的发送周期时,服务端程序就无法正确接收数据。
百度,bing上面查询问题,没有找到原因。后来在https://blog.csdn.net/FeeLang/article/details/4983317 文章里发现了我的程序问题。就是select之前没有FD_ZERO重新初始化fd_set结构体的值。但是原来没有每次初始化也能接收到数据是什么原因不知道。
示例代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static fd_set s_udpFd;
/**
* initilize global variables
*/
void init_socket_var()
{
FD_ZERO(&s_udpFd);
}
int createSocket(in_addr_t addr,int port,struct sockaddr_in* sockAddr)
{
if( sockAddr == NULL)
{
return -1;
}
int sockFd =socket(AF_INET,SOCK_DGRAM,0);
if(sockFd < 0)
{
perror("Failed to create socket.");
return -1 ;
}
memset(sockAddr, 0, sizeof(struct sockaddr_in));
// Filling server information
sockAddr->sin_family = AF_INET; // IPv4
sockAddr->sin_addr.s_addr = addr;
sockAddr->sin_port = htons(port);
return sockFd;
}
int createUdpServer(void)
{
struct sockaddr_in servaddr;
int sockFd =createSocket(INADDR_ANY,38282,&servaddr);
if(sockFd < 0)
{
printf("Failed to create server socket.");
return -1 ;
}
if (bind(sockFd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1)
{
perror("Bind failed.");
close(sockFd);
sockFd = -1;
return -1;
}
return sockFd;
}
void testSocket()
{
char *hello = "Hello from petalinux client";
struct sockaddr_in servaddr;
struct timeval timeout;
struct sockaddr clntAddr;
int result;
socklen_t len;
int maxFd;
int srvFd;
int rcvSize;
char recvbuf[1024];
fd_set exceptFds;
int cnt= 0;
int useSelect = 1;
printf("test udp send\n");
init_socket_var();
timeout.tv_sec = 1;
timeout.tv_usec = 0;
srvFd = createUdpServer();
if(srvFd < 0)
{
return;
}
printf("start setting mode\n");
if(useSelect ==1)
{
// set non block mode
int flags;
flags = fcntl(srvFd,F_GETFL,0);
if(flags<0)
{
perror("fcntl");
return;
}
printf("current flags:%d\n",flags);
flags |= O_NONBLOCK;
if( fcntl(srvFd,F_SETFL,flags) < 0)
{
perror("failed to set nonblock mode\n");
return;
}else{
printf("set nonblock mode success.\n");
}
}
maxFd = srvFd;
int sockFd = createSocket(inet_addr("10.30.130.182"),38080,&servaddr);
if(maxFd <= sockFd)
{
maxFd = sockFd +1;
}
if(sockFd < 0)
{
return;
}
while(1)
{
if( useSelect ==1){
// 需要每次都初始化fd_set的值,是否可以FD_CLR方式还没有试验。问题原因
FD_ZERO(&s_udpFd);
FD_SET(srvFd,&s_udpFd);
//timeout 应该不需要每次设置,原来的排错代码
timeout.tv_usec = 0;
timeout.tv_sec = 1;
result = select(maxFd,&s_udpFd,NULL,NULL,&timeout);
if(result < 0)
{
// 失败就退出。
perror("select failed.");
break;
}
else if(result ==0)
{
continue;
}
cnt++;
if(cnt %10 == 1){
printf("data ready %d\n",result);
}
}
//for(int i = 0; i < 2; i++ )
{
if ( (useSelect==0) || FD_ISSET(srvFd,&s_udpFd) )
{
memset( recvbuf, 0, sizeof(char) * 1024 );
//rcvSize = recv( srvFd, recvbuf, 1024, 0);
len = sizeof(clntAddr);
rcvSize = recvfrom(srvFd,recvbuf, 1024, 0,&clntAddr,&len);
if ( rcvSize < 0 )
{
perror("recv failed.\n");
}
else
{
if(rcvSize > 0)
{
struct sockaddr_in* p =(struct sockaddr_in*)(&clntAddr);
printf("from %s recv %d bytes. <= %s\n",
inet_ntoa(p->sin_addr),rcvSize,recvbuf);
sendto(sockFd,(const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
}
}
}
}
}
close(srvFd);
close(sockFd);
}