分享

Linux 客户端 Socket 非阻塞connect编程 第2页

 gljin_cn 2014-03-20
针对这种情况,unix网络编程中提出了另外3种方法,这3种方法,也是网络上给出的常用的非阻塞connect示例:

a.再调用connect一次。失败返回errno是EISCONN说明连接成功,表示刚才的connect成功,否则返回失败。 代码如下:*/
intconnect_ok;
connect(sockfd, (structsockaddr*)&serv_addr,sizeof(structsockaddr) );
switch (errno)
{
caseEISCONN:   //connect ok
printf("connect OK \n");
connect_ok=1;
break;
caseEALREADY:
connect_0k=-1
break;
caseEINPROGRESS:// is connecting, need to check again
connect_ok=-1
break;
default:
printf("connect fail err=%d \n",errno);
connect_ok=-1;
break;
}
/*如程序所示,根据再次调用的errno返回值将connect_ok的值,来进行下面的处理,connect_ok为1继续执行其他操作,否则程序结束。

但这种方法我在linux下测试了,当发生错误的时候,socket描述符(我的程序里是sockfd)变成可读且可写,但第二次调用connect 后,errno并没有返回EISCONN,,也没有返回连接失败的错误,仍旧是EINPROGRESS,而当网络不发生故障的时候,第二次使用 connect连接也返回EINPROGRESS,因此也无法通过再次connect来判断连接是否成功。

b.unix网络编程中说使用read函数,如果失败,表示connect失败,返回的errno指明了失败原因,但这种方法在linux上行不通,linux在socket描述符为可读可写的时候,read返回0,并不会置errno为错误。

c.unix网络编程中说使用getpeername函数,如果连接失败,调用该函数后,通过errno来判断第一次连接是否成功,但我试过了,无论网络连接是否成功,errno都没变化,都为EINPROGRESS,无法判断。

悲哀啊,即使调用getpeername函数,getsockopt函数仍旧不行。

综上方法,既然都不能确切知道非阻塞connect是否成功,所以我直接当描述符可读可写的情况下进行发送,通过能否获取服务器的返回值来判断是否成功。(如果服务器端的设计不发送数据,那就悲哀了。)

程序的书写形式出于可移植性考虑,按照unix网络编程推荐写法,使用getsocketopt进行判断,但不通过返回值来判断,而通过函数的返回参数来判断。

6. 用select查看接收描述符,如果可读,就读出数据,程序结束。在接收数据的时候注意要先对先前的rset重新赋值为描述符,因为select会对 rset清零,当调用select后,如果socket没有变为可读,则rset在select会被置零。所以如果在程序中使用了rset,最好在使用时候重新对rset赋值。

程序如下:*/
FD_ZERO(&rset);
FD_SET(sockfd,&rset);//如果前面select使用了rset,最好重新赋值
if( ( n =select(sockfd+1,&rset,NULL,NULL,&tval)) <=0 )
{
close(sockfd);
return-1;
}
if ((recvbytes=recv(sockfd,buf,1024,0)) ==-1)
{
perror("recv error!");
close(sockfd);
return1;
}
printf("receive num %d\n",recvbytes);
printf("%s\n",buf);
*/

linux

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多