单线程客户端处理多个socket连接的问题

微亮之光 2014-12-06 11:20:10
程序要实现的功能:现在由n个DNS权威服务器,我依次向这些服务器发送同一个DNS查询请求,每次发送完用select监听描述符集,获取最先给出的DNS应答,但是程序目前每次轮询到的给出应答的连接都是最后一个建立的描述符,但是通过wireshark抓包,在这之前已经有服务器给出应答了,为什么select没有监听到?
int s, maxfd;
int tries, ns, i;
int n, sendlen, resplen;
struct sockaddr_in nsap, from;
socklen_t nsaplen, fromlen;
struct timeval timeout;
fd_set rset;

FD_ZERO(&rset);
maxfd = -1;

/* No name servers or res_init() failure */
if (statp->nscount == 0 ) {
goto fail;
}

/*
* Send request, RETRY times, or until successful.
*/

for (tries = 0; tries < statp->retry; tries++) {

for (ns = 0; ns < statp->nscount; ns++) {
/* Use datagrams. */
if(statp->socks[ns] == -1)
{
statp->socks[ns] = socket(PF_INET,SOCK_DGRAM,0);
setnonblocking(statp->socks[ns]);

}
s = statp->socks[ns];
printf("fd %d\n",s);

nsap = statp->nsaddr_list[ns];
nsaplen = sizeof(struct sockaddr_in);
if(connect(s,(struct sockaddr *)&nsap,nsaplen) == -1)
{
fprintf(stderr,"connect error\n");
goto fail;
}

sendlen = sendto(s,(const char *)buf,buflen,0,(struct sockaddr *)&nsap,nsaplen);
if(sendlen <= 0)
{
printf("send to failed\n");
goto fail;
}

if(sendlen != buflen)
{
printf("send to error\n");
goto fail;
}

FD_SET(s, &rset);
if(s > maxfd)
maxfd = s;
timeout.tv_sec = 0;
timeout.tv_usec = 90000;
n = select(maxfd+1, &rset, NULL, NULL, &timeout);

if (n == 0) {
printf("select timeout\n");
continue;
}
if (n < 0) {

printf("select error\n");
goto fail;
}
for(i=0;i<=ns;i++)
{
if(FD_ISSET(statp->socks[i],&rset))
{
printf("active fd %d\n",statp->socks[i]);
fromlen = sizeof(from);
resplen = recvfrom(statp->socks[i], (char*)ans, anssiz,0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
printf("recvfrom error\n");
goto fail;
}
return resplen;
}

}
} /*foreach ns*/
} /*foreach retry*/
res_nclose(statp);
return -1;
fail:
res_nclose(statp);
return -1;
...全文
292 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
what was the return value from select? select might return all available "ready to read" sockets in one call
  • 打赏
  • 举报
回复
引用 2 楼 Cody2k3 的回复:
[quote=引用 楼主 u011783996 的回复:] 程序要实现的功能:现在由n个DNS权威服务器,我依次向这些服务器发送同一个DNS查询请求,每次发送完用select监听描述符集,获取最先给出的DNS应答,但是程序目前每次轮询到的给出应答的连接都是最后一个建立的描述符,但是通过wireshark抓包,在这之前已经有服务器给出应答了,为什么select没有监听到?
int s, maxfd;
	int tries, ns, i;
	int n, sendlen, resplen;
	struct sockaddr_in nsap, from;
	socklen_t nsaplen, fromlen;
	struct timeval timeout;
	fd_set rset;

	FD_ZERO(&rset);
	maxfd = -1;

	/* No name servers or res_init() failure */
	if (statp->nscount == 0 ) {
		goto fail;
	}

	/*
	 * Send request, RETRY times, or until successful.
	 */

	for (tries = 0; tries < statp->retry; tries++) {

	    for (ns = 0; ns < statp->nscount; ns++) {
			/* Use datagrams. */
			if(statp->socks[ns] == -1)
			{
				statp->socks[ns] = socket(PF_INET,SOCK_DGRAM,0);
				setnonblocking(statp->socks[ns]);

			}
			s = statp->socks[ns];
			printf("fd %d\n",s);
			
			nsap = statp->nsaddr_list[ns];
			nsaplen = sizeof(struct sockaddr_in);
			if(connect(s,(struct sockaddr *)&nsap,nsaplen) == -1)
			{
				fprintf(stderr,"connect error\n");
				goto fail;
			}
				
			sendlen = sendto(s,(const char *)buf,buflen,0,(struct sockaddr *)&nsap,nsaplen);
			if(sendlen <= 0)
			{
				printf("send to failed\n");
				goto fail;
			}

			if(sendlen != buflen)
			{
				printf("send to error\n");
				goto fail;
			}

			FD_SET(s, &rset);
			if(s > maxfd)
				maxfd = s;
			timeout.tv_sec = 0;
			timeout.tv_usec = 90000;
			n = select(maxfd+1, &rset, NULL, NULL, &timeout);
		
			if (n == 0) {
				printf("select timeout\n");
				continue;
			}
			if (n < 0) {
		
				printf("select error\n");
				goto fail;
			}
			for(i=0;i<=ns;i++)
			{	
				if(FD_ISSET(statp->socks[i],&rset))
				{
					printf("active fd %d\n",statp->socks[i]);
					fromlen = sizeof(from);
					resplen = recvfrom(statp->socks[i], (char*)ans, anssiz,0,
						   (struct sockaddr *)&from, &fromlen);
					if (resplen <= 0) {
						printf("recvfrom error\n");
						goto fail;	
					}
					return resplen;
				}
				
			}
		} /*foreach ns*/
	} /*foreach retry*/
 	res_nclose(statp);
 	return -1;
 fail:
    res_nclose(statp);
	return -1;
code 没有问题,如果总是某个dns server 先返回ready,可以调换dns server 顺序试试[/quote] does select return the available socket immediately or it could put them in a queue in a certain amount of time?
Cody2k3 2014-12-07
  • 打赏
  • 举报
回复
引用 楼主 u011783996 的回复:
程序要实现的功能:现在由n个DNS权威服务器,我依次向这些服务器发送同一个DNS查询请求,每次发送完用select监听描述符集,获取最先给出的DNS应答,但是程序目前每次轮询到的给出应答的连接都是最后一个建立的描述符,但是通过wireshark抓包,在这之前已经有服务器给出应答了,为什么select没有监听到?
int s, maxfd;
	int tries, ns, i;
	int n, sendlen, resplen;
	struct sockaddr_in nsap, from;
	socklen_t nsaplen, fromlen;
	struct timeval timeout;
	fd_set rset;

	FD_ZERO(&rset);
	maxfd = -1;

	/* No name servers or res_init() failure */
	if (statp->nscount == 0 ) {
		goto fail;
	}

	/*
	 * Send request, RETRY times, or until successful.
	 */

	for (tries = 0; tries < statp->retry; tries++) {

	    for (ns = 0; ns < statp->nscount; ns++) {
			/* Use datagrams. */
			if(statp->socks[ns] == -1)
			{
				statp->socks[ns] = socket(PF_INET,SOCK_DGRAM,0);
				setnonblocking(statp->socks[ns]);

			}
			s = statp->socks[ns];
			printf("fd %d\n",s);
			
			nsap = statp->nsaddr_list[ns];
			nsaplen = sizeof(struct sockaddr_in);
			if(connect(s,(struct sockaddr *)&nsap,nsaplen) == -1)
			{
				fprintf(stderr,"connect error\n");
				goto fail;
			}
				
			sendlen = sendto(s,(const char *)buf,buflen,0,(struct sockaddr *)&nsap,nsaplen);
			if(sendlen <= 0)
			{
				printf("send to failed\n");
				goto fail;
			}

			if(sendlen != buflen)
			{
				printf("send to error\n");
				goto fail;
			}

			FD_SET(s, &rset);
			if(s > maxfd)
				maxfd = s;
			timeout.tv_sec = 0;
			timeout.tv_usec = 90000;
			n = select(maxfd+1, &rset, NULL, NULL, &timeout);
		
			if (n == 0) {
				printf("select timeout\n");
				continue;
			}
			if (n < 0) {
		
				printf("select error\n");
				goto fail;
			}
			for(i=0;i<=ns;i++)
			{	
				if(FD_ISSET(statp->socks[i],&rset))
				{
					printf("active fd %d\n",statp->socks[i]);
					fromlen = sizeof(from);
					resplen = recvfrom(statp->socks[i], (char*)ans, anssiz,0,
						   (struct sockaddr *)&from, &fromlen);
					if (resplen <= 0) {
						printf("recvfrom error\n");
						goto fail;	
					}
					return resplen;
				}
				
			}
		} /*foreach ns*/
	} /*foreach retry*/
 	res_nclose(statp);
 	return -1;
 fail:
    res_nclose(statp);
	return -1;
code 没有问题,如果总是某个dns server 先返回ready,可以调换dns server 顺序试试

23,217

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧