关于select的问题

renshuming 2008-06-02 11:15:18
在局域网内,客户端不知道服务器端的ip地址,所以用ip地址依次尝试的方式连接服务器端,将connect设为非阻塞,用select控制超时。现在有如下几个困惑请教各位:

在以下列举的情况中,客户端“不能正常连上服务器端”,但这里的“不能正常连上”指的是select返回值不正确,即不为大于0的值。但是服务器端的打印显示accept是成功了的。

1,假如服务器端ip地址为...101,我从...92开始依次尝试连接(101是尝试连接的第10个ip),尝试到ip...101时能够连接成功(即select返回大于0的值)。但是只要从小于92的ip开始依次尝试连接,就不能成功(select的超时时间设为100ms,但是我试着改为200、300ms,照样不行);
2,如果执行调试,即单步跟踪什么的,能连接成功;
3,如果将select的超时改为2秒以上,就能一切正常。

我对以上的现象相当困惑,请各位帮助。

关键部分代码如下:
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct fd_set writeSet;
struct timeval timeConn;
u_long opt = 1;

ioctlsocket(sock, FIONBIO, &opt);

writeSet.fd_count = 1;
writeSet.fd_array[0] = sock;

/*现在是200ms,不行,改为几百ms都不行*/
timeConn.tv_sec = 0;
timeConn.tv_usec = 200 * 1000;

/*这样就行了*/
/*timeConn.tv_sec = 2;
timeConn.tv_usec = 0;*/

if (0 != connect(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
if (select(1, NULL, &writeSet, NULL, &timeConn) > 0)
{
opt = 0;
ioctlsocket(sock, FIONBIO, &opt);
printf("Connect succeed!\n");
}
else
{
printf("Connect failed!\n");/*不正常的时候分支走到这里,但是服务器端已经accept成功了……*/
closesocket(sock);
}
}
else
{
opt = 0;
ioctlsocket(sock, FIONBIO, &opt);
printf("Connect succeed!\n");
}
...全文
66 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
laibach0304 2008-08-19
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <io.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

int connect_nonb(
int sockfd,
const struct sockaddr *saptr,
socklen_t salen,
int nsec
)
{
int flags, n, error;
socklen_t len;
fd_set rset, wset;
struct timeval tval;

flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

error = 0;
if ( (n = connect(sockfd, saptr, salen)) < 0)
if (errno != EINPROGRESS)
return (-1);

/* Do whatever we want while the connect is taking place. */

if (n == 0)
goto done; /* connect completed immediately */

FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
tval.tv_sec = nsec;
tval.tv_usec = 0;

if ( (n = select(sockfd + 1, &rset, &wset, NULL,
nsec ? &tval : NULL)) == 0)
{
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return (-1);
}

if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
{
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return (-1); /* Solaris pending error */
}
else
return -1;

done:
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */

if (error)
{
close(sockfd); /* just in case */
errno = error;
return (-1);
}
return (0);
}


这是一个带超时的connect例子,lz注意重点在几个边界条件上。
laibach0304 2008-08-19
  • 打赏
  • 举报
回复
你这个代码很不健壮,而且有错误
难怪会出错

建议e去读一下unix网络编程的16.3,如何实现一个正确的带超市的connct
laibach0304 2008-08-19
  • 打赏
  • 举报
回复
你这个代码很不健壮,而且有错误
难怪会出错

建议e去读一下unix网络编程的16.3,如何实现一个正确的带超市的connct
lllxy 2008-08-19
  • 打赏
  • 举报
回复
select 的函数使用的时候最好处理三种情况: 1.成功; 2. 超时; 3.失败,看你的代码只有两种情况,因此看不出是超时还是失败,搂住可再根据我的想法作个测试

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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