免费注册 查看新帖 |

Chinaunix

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

请问perl不使用【IO::Socket、POE】,如何建立非阻塞socket? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-06-01 16:04 |只看该作者 |倒序浏览
RT,

另外,connect时候,不使用alarm,如何设置超时?

论坛徽章:
0
2 [报告]
发表于 2010-06-01 16:33 |只看该作者
不用IO::Socket也起码要用到Socket.pm吧,否则如何进行socket编程?
非阻塞Socket与用不用IO::Socket无关,它是一套机制,需要相关技巧来实现,ie, IO::Select.
可google with "perl non-blocking socket".

论坛徽章:
0
3 [报告]
发表于 2010-06-01 17:03 |只看该作者
  1. # create a client socket for caller.
  2. sub client_socket()
  3. {
  4.     my ($proto) = -1;
  5.     $proto = getprotobyname('tcp');
  6.     my ($host) = shift(@_);
  7.     my ($port) = shift(@_);
  8.     #my ($hd_socket) = undef ;

  9.     # get the address of socket handle.
  10.     my ($hd_socket) = shift(@_) ;

  11.     $host = inet_aton($host);

  12.     # port on the IP address for the remote host
  13.     my $servaddr = sockaddr_in($port, $host);

  14.     socket($$hd_socket, PF_INET, SOCK_STREAM, $proto) or die "Unable to create socket: $!";
  15.     setsockopt ($$hd_socket, SOL_SOCKET, SO_REUSEADDR,1) or die "setsockopt err";

  16.     bind($$hd_socket, sockaddr_in(0, inet_aton($ip_bind))) or die "Unable to bind: $!";
  17. my $t_connect_ret = connect($$hd_socket, $servaddr) ; #or die "Unable to connect: $!";
  18. return  $t_connect_ret ;
  19. }
复制代码
我的问题是在 connect 时候挂死,原因是传入IP不可达,请问有没有办法为此connect设置超时(不想使用alarm)?
这样就不会阻塞在这里了。

论坛徽章:
0
4 [报告]
发表于 2010-06-01 18:56 |只看该作者

  1. #!/bin/env perl

  2. use strict;
  3. use warnings;
  4. use Socket;
  5. use Fcntl;
  6. use IO::Select;

  7. my $socket = &socket_init("192.168.2.3", 80, 5);

  8. sub socket_init
  9. {
  10.         my ($host, $port, $timeout) = @_;
  11.         my $socket;
  12.         my $dest;

  13.         if (socket($socket, PF_INET, SOCK_STREAM, 6))
  14.         {
  15.                 if ($^O eq 'MSWin32')
  16.                 {
  17.                         my $nonblocking = pack('L', 1);
  18.                         ioctl($socket, 0x8004667e, unpack('I', pack('P', $nonblocking)));
  19.                 }
  20.                 else
  21.                 {
  22.                         fcntl($socket, F_SETFL, fcntl($socket, F_GETFL, 0) | O_NONBLOCK);
  23.                 }

  24.                 my $dest = sockaddr_in($port, inet_aton($host));
  25.                 connect($socket, $dest);
  26.                 my $select = new IO::Select($socket);
  27.                 my ($read_set, $write_set, $error_set) = IO::Select->select(undef, $select, $select, $timeout);
  28.                 if ($#$write_set > -1 and $#$error_set == -1)
  29.                 {
  30.                         ;
  31.                 }
  32.                 else
  33.                 {
  34.                         warn "$^E\n";
  35.                         $socket = undef;
  36.                 }
  37.         }

  38.         return $socket;
  39. }
复制代码

论坛徽章:
0
5 [报告]
发表于 2010-06-01 19:07 |只看该作者
1 把套接字句柄设成非阻塞的,这样子connect是马上返回的。
2 用IO::Select去监视句柄的状态,当正常连接上时,$#$write_set大于-1而且$#$error_set等于-1。当$timeout秒没连接上时,IO::Select返回-1 -1 -1

论坛徽章:
0
6 [报告]
发表于 2010-06-02 08:04 |只看该作者
use Coro::Socket;
use Coro::Timer;

10行代码搞定

论坛徽章:
0
7 [报告]
发表于 2010-06-02 10:00 |只看该作者
已经通过select方式搞定。
谢谢各位的帮忙!
  1.     connect($$hd_socket, $servaddr) ;
  2.     my $sel_socket = new IO::Select($$hd_socket);
  3.     my ($read_set, $write_set, $error_set) = IO::Select->select($sel_socket, $sel_socket, $sel_socket, $TIMEOUT);
  4.     if ($#$write_set > -1 and $#$error_set == -1)
  5.     {
  6.         if ($#$read_set == 0 || $sel_socket->can_read(0))
  7.         {
  8.             print "connect refused.\n";
  9.             $$hd_socket = undef;
  10.             return -1;
  11.         }
  12.         return 1;
  13.     }
  14.     else
  15.     {
  16.         print "unreachable host.\n";
  17.         $$hd_socket = undef;
  18.         return -1;
  19.     }
复制代码
PS: 是不是非阻塞socket,使用sysread读写是不是需要特殊处理?
直接调用 sysread($hd_tmp, $$buf_recv, 204  为啥收不到东西?

论坛徽章:
0
8 [报告]
发表于 2010-06-02 10:03 |只看该作者
已经通过select方式搞定。
谢谢各位的帮忙!PS: 是不是非阻塞socket,使用sysread读写是不是需要特殊处理 ...
suposonic 发表于 2010-06-02 10:00



最简单的 connect上以后 把套接字句设再设为阻塞式

非阻塞的,每次读写前都要用select判断可读写

论坛徽章:
0
9 [报告]
发表于 2010-06-02 10:30 |只看该作者
这个方式我试了,但是貌似不行。。。
我的方式如下:
  1. my $save_fl = fcntl($$hd_socket, F_GETFL, 0);
  2. fcntl($$hd_socket, F_SETFL, fcntl($$hd_socket, F_GETFL, 0) | O_NONBLOCK);
复制代码
然后,我设置回来的时候使用如下方法:
  1. fcntl($$hd_socket, F_SETFL,  $save_fl );
复制代码
貌似不好用,请问是不是哪里处理的不妥?

论坛徽章:
0
10 [报告]
发表于 2010-06-02 10:54 |只看该作者
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP