在局域网内,客户端不知道服务器端的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");
}

解决方案 »

  1.   

    select 的函数使用的时候最好处理三种情况: 1.成功; 2. 超时; 3.失败,看你的代码只有两种情况,因此看不出是超时还是失败,搂住可再根据我的想法作个测试
      

  2.   

    你这个代码很不健壮,而且有错误
    难怪会出错建议e去读一下unix网络编程的16.3,如何实现一个正确的带超市的connct
      

  3.   

    你这个代码很不健壮,而且有错误
    难怪会出错建议e去读一下unix网络编程的16.3,如何实现一个正确的带超市的connct
      

  4.   

    #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注意重点在几个边界条件上。