免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 18692 | 回复: 24
打印 上一主题 下一主题

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

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-07 13:00 |只看该作者 |倒序浏览
client端使用非阻塞socket进行connect时,即使connect的server ip 不存在,select也会返回1,只有到send时才真正失败,这到底是为什么?
code如下:
memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_family = PF_UNSPEC;
        hints.ai_protocol = IPPROTO_TCP;       
        //hints.ai_flags = AI_NUMERICHOST;

        /* address info of server */
        ret = getaddrinfo(pconinfo->dev, pinfo->szdst, &hints, &pres);
        if (ret) {
                trace4(LVL_ERROR, LOGARG, "getaddinfo(%s %s) failed(%d %d).", pconinfo->dev, pinfo->szdst, ret, errno);
                ret = AC_ERROR_SOCK;
                goto exit;
        }

论坛徽章:
0
2 [报告]
发表于 2007-03-07 13:02 |只看该作者
sorry, 刚刚没发完,接上:
sock = socket(pres->ai_family, pres->ai_socktype, pres->ai_protocol);
        if (sock == -1) {
                trace4(LVL_ERROR, LOGARG, "socket() failed(%d).", errno);
                ret = AC_ERROR_SOCK;
                goto exit;
        }

if (pres->ai_family== AF_INET) {
                inet_pton(AF_INET, mydev, &(other_ip.s6_addr32[3]));               
                memset(&socketaddr, 0, sizeof(struct sockaddr_in));
                  socketaddr.sin_family = AF_INET;
                memcpy(&(socketaddr.sin_addr), &(other_ip.s6_addr32[3]), sizeof(struct sockaddr_in));
                   socketaddr.sin_port = htons(0);
                   ret = bind( sock, (struct sockaddr*)&socketaddr, sizeof(struct sockaddr_in));
        }
        else {
                inet_pton(AF_INET6, mydev, &(other_ip.s6_addr32));               
               memset(&socketaddr6, 0, sizeof(struct sockaddr_in6));
               socketaddr6.sin6_family = AF_INET6;
               socketaddr6.sin6_flowinfo = 0;
               socketaddr6.sin6_port = htons(0);
               memcpy(&(socketaddr6.sin6_addr),&other_ip, sizeof(struct in6_addr));
               ret = bind( sock, (struct sockaddr*) &socketaddr6, sizeof(struct sockaddr_in6));        
        }
        if (ret != 0) {
                trace4(LVL_ERROR, LOGARG, "bind() failed(%d).", errno);
                ret = AC_ERROR_SOCK;
                goto exit;
        }
        if(flag == USE_SHM)
        {
                listin_sockets(*ppsockets);
        }
        /* connect */
        /*modify for control connect time by zhaoyh on 20070305*/
        blockFlag = fcntl(sock, F_GETFL);
        blockFlag |= O_NONBLOCK;
        fcntl( sock, F_SETFL, blockFlag);
       
        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, NULL, &fd, 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
                        {
                                ret = 0;
                        }

                }
                else if(ret ==0)
                {
                        trace4(LVL_ERROR, LOGARG, "select(%d,...) timeout.", sock);
                        ret = AC_ERROR_NOTCONN;       
                }
                else
                {
                        trace4(LVL_ERROR, LOGARG, "select(%d,...) failed,errno<%d>.", sock, errno);
                        ret = AC_ERROR_NOTCONN;
                }
               
                if(ret == 0)
                {
       
                        /*clear noblock I/0*/
                        blockFlag = fcntl(sock, F_GETFL);
                        blockFlag = blockFlag & ~O_NONBLOCK;
                        fcntl( sock, F_SETFL, blockFlag );
                }
                else
                {

                        goto exit;
                }
        }
        else {

                /*clear noblock I/0*/
                blockFlag = fcntl(sock, F_GETFL);
                blockFlag = blockFlag & ~O_NONBLOCK;
                fcntl( sock, F_SETFL, blockFlag );
        }

论坛徽章:
0
3 [报告]
发表于 2007-03-07 13:56 |只看该作者
个人的理解:
连接一个不存在的ip的时候,connect返回出错。这个时候socket变为可写或者可读
用select自然就返回正确了
事实上,在select返回后,应该用getsockopt看看有没有出错

隔了大半年了,记不太清楚了,建议lz翻书看看socket在什么时候会变为可读或者可写
有些情况下用select返回可写并不是真正的可写,只是通告socket上有事件发生了

以上纯属抛砖引玉

论坛徽章:
0
4 [报告]
发表于 2007-03-07 14:40 |只看该作者
多谢.
我再用getsockopt试试,本来以为用connect->select之后,用FD_ISSET检查就够了呢,
呵呵

论坛徽章:
0
5 [报告]
发表于 2007-03-07 14:48 |只看该作者
不过,还有一个问题,当连接的对端
的网络暂时出现问题时,select并没有阻塞指定的时间,而是
直接返回,这样也是有问题的,因为如果在指定时间内网络恢复,那应该怎么知道呢?

论坛徽章:
0
6 [报告]
发表于 2007-03-07 15:15 |只看该作者
没有阻塞指定的时间?
这个我就不清楚了
帮你顶
等高手有空回答

论坛徽章:
0
7 [报告]
发表于 2007-03-07 17:58 |只看该作者
select做的事情只是看你的socket可用与否,跟网络怎么样没有任何关系。只要你的socket在bind正常后,基本上就可以用了,select当然会返回1。当你的缓冲区满了的时候,他才会返回错误值。至于怎么知道能连上,就要知道socket可不可以读了。。可以阻塞select一段你指定的时间,检测socket可否进行读操作了

论坛徽章:
0
8 [报告]
发表于 2007-03-08 10:12 |只看该作者
我已经将select的检查改为了对write-fset的检查,
现在即使server端网络是断的,select可以阻塞了,但是
select还是返回1,而且也能通过getsockopt检查,
这是为什么啊?

论坛徽章:
0
9 [报告]
发表于 2007-03-08 11:05 |只看该作者
帮你顶,等高人ing...........!

论坛徽章:
0
10 [报告]
发表于 2007-03-08 11:06 |只看该作者
看了楼主的帖子,感觉你对协议还不是非常的了解,下面说说我的一些认识,希望对你有用。
一、连接有两类,一类是实连接,例如打固定电话,在线路上固定占用了一个通道,这个通道在通话期间是一直存在的;另一类是虚连接,TCP的连接就是这种,客户端连接到服务器端后,连接虽然建立了,但是实际上物理上并不是真正存在这样的通道。他们之间的连接是靠之间的数据包的往来确立的。所以,对于两台机器之间网络断掉,相互是不可能知道的,并没有什么东西能通知双方,而只能是通过事后发送数据包才能出现了问题,具体什么问题还需要进行判断。一般tcp连接都需要使用一些技术手段来维持,有两种方法:一是利用tcp协议本身,设置SO_KEEPALIVE;二是应用层增加链路检测包。
二、要明白应用进程和内核之间的区别,我们写一般的sokect程序,应用程序只是调用系统提供的函数接口,真正的实现都是内核来完成的,由于网络的特殊性,socket函数有着自己的一些特性,其收发函数都只是本机之间的操作,并不真正涉及到网络。例如send发送函数,返回成功只是表示我们把数据给了内核的发送缓冲区,并不是已经从网卡发送出去了,至于是否发送成功,send函数本身是不可能获得的;接收函数类似,只是表示从内核接收缓冲区拷贝到应用进程成功。
建议仔细看看相关方面的书籍。

[ 本帖最后由 Sorehead 于 2007-3-8 11:15 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP