connect与select函数用法

本文介绍了一个使用非阻塞套接字进行连接的C程序实例,该程序通过select机制监测连接是否完成,并通过getsockopt检查连接状态。适用于Linux环境。

#include   <stdlib.h>
#include   <stdio.h>
#include   <unistd.h>
#include   <fcntl.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <errno.h>
#include   <time.h>
#include   <arpa/inet.h>

int   main(int   argc,   char   *argv[])  
{
int   fd,   retval;  
struct   sockaddr_in   addr;
struct   timeval   timeo   =   {3,   0};  
socklen_t   len   =   sizeof(timeo);
fd_set   set;  

fd   =   socket(AF_INET,   SOCK_STREAM,   0);
if   (argc   ==   4)   timeo.tv_sec   =   atoi(argv[3]);  
int   savefl   =   fcntl(fd,F_GETFL);
fcntl(fd,   F_SETFL,   savefl   |   O_NONBLOCK);
addr.sin_family   =   AF_INET;
addr.sin_addr.s_addr   =   inet_addr(argv[1]);
addr.sin_port   =   htons(atoi(argv[2]));
printf( "%d/n ",   time(NULL));  
if   (connect(fd,   (struct   sockaddr*)&addr,   sizeof(addr))   ==   0)  
{  
close(fd);
printf( "connected..1/n ");
return   0;  
}

if   (errno   !=   EINPROGRESS)
{
close(fd);
perror( "connect..2 ");
return   -1;  
}
FD_ZERO(&set);
FD_SET(fd,   &set);
retval   =   select(fd   +   1,   NULL,   &set,   NULL,   &timeo);  
if   (retval   ==   -1)
{  
close(fd);
perror( "select ");  
return   -1;
}  
else   if(retval   ==   0)  
{  
close(fd);
fprintf(stderr,   "timeout/n ");
printf( "%d/n ",   time(NULL));
return   0;
}
printf( "connected   ..   3/n ");
fcntl(fd,   F_SETFL,savefl);
close(fd);
return   0;  
}

1.   OS:linux   kenerl   2.6   (fedora.unix-center.net)
2.   测试连接   (202.108.22.43:80,202.108.22.43:8000,)   百度,程序正常,其他机器也正常
3.   但是测试   127.0.0.1   任何端口都说能连接上,非常奇怪

 

 

 

 

今天仔细   看了   man   connect,明白了错误的原因:
EINPROGRESS
                            The     socket     is     non-blocking   and   the   connection
                            cannot   be   completed   immediately.     It   is   possible
                            to       select(2)     or     poll(2)     for     completion     by
                            selecting     the       socket       for       writing.       After
                            select(2)     indicates     writability,     use   getsock-
                            opt(2)   to   read     the     SO_ERROR     option     at     level
                            SOL_SOCKET     to     determine   whether   connect()   com-
                            pleted   successfully   (SO_ERROR   is   zero)   or   unsuc-
                            cessfully     (SO_ERROR     is     one   of   the   usual   error
                            codes   listed   here,   explaining   the   reason   for   the
                            failure).
修改如下:
#include   <stdlib.h>
#include   <stdio.h>
#include   <unistd.h>
#include   <fcntl.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <errno.h>
#include   <time.h>
#include   <arpa/inet.h>

int   main(int   argc,   char   *argv[])
{
int   fd,   retval;
struct   sockaddr_in   addr;
struct   timeval   timeo   =   {3,   0};
socklen_t   len   =   sizeof(timeo);
fd_set   set;

fd   =   socket(AF_INET,   SOCK_STREAM,   0);
if   (argc   ==   4)   timeo.tv_sec   =   atoi(argv[3]);
int   savefl   =   fcntl(fd,F_GETFL);
fcntl(fd,   F_SETFL,   savefl   |   O_NONBLOCK);
addr.sin_family   =   AF_INET;
addr.sin_addr.s_addr   =   inet_addr(argv[1]);
addr.sin_port   =   htons(atoi(argv[2]));
printf( "%d/n ",   time(NULL));
if   (connect(fd,   (struct   sockaddr*)&addr,   sizeof(addr))   ==   0)
{
close(fd);
printf( "connected..1/n ");
return   0;
}

if   (errno   !=   EINPROGRESS)
{
close(fd);
perror( "connect..2 ");
return   -1;
}
FD_ZERO(&set);
FD_SET(fd,   &set);
retval   =   select(fd   +   1,   NULL,   &set,   NULL,   &timeo);
if   (retval   ==   -1)
{
close(fd);
perror( "select ");
return   -1;
}
else   if(retval   ==   0)
{
close(fd);
fprintf(stderr,   "timeout/n ");
printf( "%d/n ",   time(NULL));
return   0;
}

if(FD_ISSET   (fd,&set))             //||   FD_ISSET(SockFd,&wset))
{
int   error   =   0;
socklen_t   len   =   sizeof   (error);
if(getsockopt(fd,   SOL_SOCKET,   SO_ERROR,   &error,   &len)   <   0)
{
printf   ( "getsockopt   fail,connected   fail/n ");
return   -1;
}

if   (error   ==   ETIMEDOUT)
{
printf   ( "connected   timeout/n ");
}

if(error   ==   ECONNREFUSED)
{
printf( "No   one   listening   on   the   remote   address./n ");
return   -1;
}
}
printf   ( "connected   ..   3/n ");
fcntl(fd,   F_SETFL,   savefl);
close   (fd);

return   0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值