单线程客户端处理多个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;
...全文
280 3 打赏 收藏 转发到动态 举报
写回复
用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 顺序试试
环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个是SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员

23,110

社区成员

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

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