免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: coconutmm
打印 上一主题 下一主题

client端使用非阻塞socket进行connect时select遇到的奇怪问题 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2007-03-08 13:13 |只看该作者
谢谢Sorehead 的说明.

今天也看到了一些关于send,recv的说明,的确是这样的
但是connect好象不一样吧,怎样才能利用非阻塞模拟出
时间可控的connect呢?

另外,能推荐几本相关的书么?

论坛徽章:
0
12 [报告]
发表于 2007-03-08 15:02 |只看该作者
基本就是这样的:

[code]
。。。。。。
if(select(.............) == -1) return -1;
if(FD_ISSET(s, &wfds)) {
    if(getpeername(s, ...) == -1) { .... return -1; }

    set O_NONBLOCK off;
    //连接成功
    return 0;
}


[code]

论坛徽章:
0
13 [报告]
发表于 2007-03-08 15:15 |只看该作者
使用getsockopt不可以么?
好多书上都是这么说的啊?

论坛徽章:
0
14 [报告]
发表于 2007-03-08 15:18 |只看该作者
可以。原理一样

论坛徽章:
0
15 [报告]
发表于 2007-03-08 15:48 |只看该作者
ret = connect(sock, pres->ai_addr, pres->ai_addrlen);
        if (ret == -1) {
                FD_ZERO(&fd);
                FD_SET(sock, &fd);
                timeout.tv_sec = _aclinfo.tout;
                timeout.tv_usec =0;
                ret = select(sock + 1, &fd, NULL, NULL, &timeout);
                if(ret > 0)
                {
                        if(FD_ISSET(sock, &fd) == 0)
                        {
                                trace4(LVL_ERROR, LOGARG, "socket<%d> is not in fd !", sock, errno);
                                ret = AC_ERROR_NOTCONN;
                        }
                        else
                        {
                                len = sizeof(err);
                                if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0){
                                                                                ret = AC_ERROR_NOTCONN;
                                }       
                                ret = 0;
                        }

                }

这样,getsockopt还是无法检测出网络断开的情况,哪里不对啊?

论坛徽章:
0
16 [报告]
发表于 2007-03-09 09:18 |只看该作者
我对getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len)的处理进行了修改,不是判断返回值 < 0,而是判断err的植是否大于0.
client端似乎可以了,但是现在server端(阻塞)却在accept后进行select很容易超时或者recv=0.
这是为什么啊?

高手能不能指点一下,client在select设置成非阻塞时,server端阻塞,应该注意哪些呢?

论坛徽章:
0
17 [报告]
发表于 2007-03-09 11:18 |只看该作者
网络编程客户端程序和服务器端程序是完全独立,不用综合考虑,他们各是各的,完全可以用不同的技术手段实现。
connect函数应用在tcp协议上会导致三段握手,与服务器端有数据交互,建立连接,这个是内核自身完成,成功或者失败会返回给应用进程。
对于select和接下来的操作,必须放在一个死循环中来做,并要对接收到的数据进行判断才行。如果客户端断开了连接,select也会返回,但是应用进程是收不到具体数据的。
unix下主要有5种i/o模型:阻塞、非阻塞、i/o复用(实际上就是阻塞,只是可以对多个io进行操作)、信号驱动和异步方式(这种方式好像还没有真正实现的)。用那种方式要看要做什么,数据量有多大,并不是越高级就越好,适用就可以。越高级,程序就越复杂,编程难度增加很多,要考虑的地方就越多,也越容易出现问题。
推荐一本书:《UNIX网络编程》、英文版《Unix Network Programming》

论坛徽章:
0
18 [报告]
发表于 2007-03-09 11:47 |只看该作者

非阻塞connect 不是用 select 判断的。

反复 connect, 直到返回 EISCONN.
int connect_socket_timeout(int sockfd,char *dest_host, int port, int timeout)
{
    struct sockaddr_in address;
    struct in_addr inaddr;
    struct hostent *host;
    int  err, noblock=1 , connect_ok=0, begin_time=time(NULL);
    log_debug("connect_socket to %s:%d\n",dest_host,port);                                                          
    if (inet_aton(dest_host, &inaddr))
    {       
//        log_debug("inet_aton ok now gethostbyaddr %s\n",dest_host);
        memcpy(&address.sin_addr, &inaddr, sizeof(address.sin_addr));
    }
    else
    {
        log_debug("inet_aton fail now gethostbyname %s \n",dest_host);
        host = gethostbyname(dest_host);
        if (!host) {
                        /* We can't find an IP number */
            log_error("error looking up host  %s : %d\n",dest_host,errno);
            return -1;
        }                                                               
        memcpy(&address.sin_addr, host->h_addr_list[0], sizeof(address.sin_addr));
    }
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    /* Take the first IP address associated with this hostname */
        ioctl(sockfd,FIONBIO,&noblock);
   
/** connect until timeout */
/*
EINPROGRESS                A nonblocking socket connection cannot be completed immediately.
EALREADY                The socket is nonblocking and a        previous connection attempt has not been completed.
EISCONN                        The socket is already connected.
*/
                if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)
                {
                        err = errno;
                        if (err != EINPROGRESS)
                        {
                                log_error("connect = %d connecting to host %s\n", err,dest_host);
                        }
                        else
                        {
//                                log_notice("connect pending, return %d \n", err);
                                while (1) /* is noblocking connect, check it until ok or timeout */
                                {
                                        connect(sockfd, (struct sockaddr *) &address, sizeof(address));
                                        err = errno;
                                        switch (err)
                                        {
                                                case EISCONN:   /* connect ok */
                                                        connect_ok = 1;
                                                        break;
                                                case EALREADY:  /* is connecting, need to check again */
//                                                        log_info("connect again return EALREADY check again...\n");
                                                        usleep(50000);
                                                        break;
//                                                default:   /* failed, retry again ? */
                                                        log_error("connect fail err=%d \n",err);
//                                                        connect_ok = -1;
//                                                        break;
                                        }
                                        if (connect_ok==1)
                                        {
//                                            log_info ("connect ok try time =%d \n", (time(NULL) - begin_time) );
                                            break;
                                        }
                                        if (connect_ok==-1)
                                        {
                                            log_notice ("connect failed try time =%d \n", (time(NULL) - begin_time) );
                                            break;
                                        }
                                        if ( (timeout>0) && ((time(NULL) - begin_time)>timeout) )
                                        {
                                            log_notice("connect failed, timeout %d seconds\n", (time(NULL) - begin_time));
                                            break;
                                        }
                                }
                        }
                }
                else        /* Connect successful immediately        */
                {
//                    log_info("connect immediate success to host %s\n", dest_host);
                    connect_ok = 1;
                }
/** end of try connect */
        return ((connect_ok==1)?sockfd:-1);
}

论坛徽章:
0
19 [报告]
发表于 2007-03-09 13:44 |只看该作者
谢谢connet (help u & me)  

反复connect好象可行,我再试试.
但是,connect之后,使用select等待检测connect的连接状况不行
么?

论坛徽章:
0
20 [报告]
发表于 2008-12-10 14:15 |只看该作者
原帖由 coconutmm 于 2007-3-9 13:44 发表
谢谢connet (help u & me)  

反复connect好象可行,我再试试.
但是,connect之后,使用select等待检测connect的连接状况不行
么?



connect 后,如何用select 检测connect的链接情况? (1: 超时 2: 失败 3: 成功);

顶.....
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP