client端使用IO::Select与阻塞问题

client端使用IO::Select与阻塞问题

以前从来没在客户端使用过IO::Select,今天刚好没事做个测试,结果很迷茫,需要人帮忙解答。判断是否连接成功,是判断can_write,对吧?这个大前提应该没错。我用的perl 5.8.8。首先IO::Socket::INET建立socket,设置为不阻塞,然后下面用select来判断can_write,结果不管什么端口都立即返回为连接成功。只有当socket设置为阻塞的时候,下面用select判断出来的才准确。

这里,刚好和我认为的相反。如果上面socket要阻塞了,下面才能用select判断是否连接成功,似乎有点晕。(当然,我知道select一般是用来轮询socket转发数据之类的)C语言或者C#都可以通过select来判断是否连接成功或者连接断开。perl里面是我做得不对么?

thx!
你的程序有问题。
多谢flw的回答,不好意思,没有把代码贴出来。

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl

use warnings;
use strict;
use IO::Select;
use IO::Socket::INET;
use Data::Dumper;

my $host = 'www.icylife.net';
my $port = 23456;

my $sock;

$sock = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => 'tcp', Blocking => '0' );

my $select = IO::Select->new( $sock );
my @writes = $select->can_write( 4 );

if( scalar( @writes ) > 0 )
{
        print Dumper( @writes );

        $sock->close( );
        print "Connect to $port ok!\n";
}
else
{
        print "Connect to $port timeout!\n";
}

你的程序逻辑有问题。
仅仅 can_write 返回并不意味着连接建立成功。
还得判断 socket 状态或者错误号才行。

在你的 if 分支里加入 say $sock->sockopt( SO_ERROR ); 试试。

建议读读 APUE 或者 UNP
恩,这里确实写得不对,原来我下的Network Programming with perl不全。
现在下了完整版的,不过代码还是有问题。

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl

use IO::Socket;
use Errno qw(EWOULDBLOCK EINPROGRESS);
use IO::Select;
use Data::Dumper;
use warnings;
use strict;

my $host = '124.205.37.93';
my $port = 80;
my $TIMEOUT = 4;

my $sock = IO::Socket::INET->new( Proto => 'tcp', Type  => SOCK_STREAM ) or die $@;

$sock->blocking(0);  # nonblocking mode

my $addr = sockaddr_in( $port, inet_aton($host) );
my $result = $sock->connect($addr);

unless($result)
{
        print Dumper($!);
        print Dumper(EINPROGRESS);

        die "Can't connect: $!" unless $! != EINPROGRESS;

        my $s = IO::Select->new($sock);
        die "timeout!" unless $s->can_write($TIMEOUT);
        unless ($sock->connected)
        {
                $! = $sock->sockopt(SO_ERROR);
                die "Can't connect: $!"
        }
        print "Connect ok using non-block!\n";
}
print "Connect ok!\n";

按照书上的意思,应该走到unless($result)里面去,但是实际没有……

我先怀疑是因为马上成功了,但是把80改成2345之类的端口,还是没有走进unless($result)分支。
另外,书上是die "Can't connect: $!" unless $! == EINPROGRESS;不过我觉得应该是die "Can't connect: $!" unless $! != EINPROGRESS;
最新测试,windows是正常的,FreeBSD和Mandriva Linux有问题。