petalinux 创建UDP服务端时,select函数不起作用故障解决一例

    这几天在搞赛灵思公司的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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <fcntl.h>
#include <time.h>

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);

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值