0

我有以下 Perl 问题:我正在尝试构建一个简单的支持网络的转发器/消费者脚本。

  • 转发器部分循环并调用本地阻塞函数以检索新字符串(即,从现有库中)

  • 消费者部分由一个服务器组成,多个客户端可以连接到服务器(TCP 套接字)

  • 这个想法是转发器部分检索到的每条消息都被传递给客户端,即转发到所有连接的客户端套接字。

我查看了线程/共享变量,但不能以这种方式共享套接字。我还查看了 POE TCP 转发示例(http://poe.perl.org/?POE_Cookbook/TCP_Forwarding),但在那里,我没有找到如何启动一个仍然可以使用发送到 %clients 或poe_kernel 在这个具体的例子中(也许有办法......)。

简而言之:

  1. 我需要分叉或使用其他一些线程机制来首先启动转发器并在检索功能上启动循环
  2. 我需要将检索到的数据交给所有连接的客户/消费者。

这是我打算做的(注意:抽象代码):

$pid = fork();

if ($pid == 0)
{
  # forwarder/producer thread
  while(1)
  {
    $string = blocking_receive_function();
    foreach(@clients)
    {
      print($_ "$string");
    }
  }
}
else
{
  # start server and add clients to consumer list
  $server = IO::Socket::INET->new( ... );
  while ($client = $server->accept()) {
    push(@clients, $client);
    # fork for this client (to allow others) and 
    # wait for specific client it closes connection
  }
}

非常感谢任何有关实施此类应用程序的良好有效方式的建议/建议!

4

2 回答 2

2

好的,有不止一种方法可以做到这一点。但恕我直言,最简单的是使用 Coro。

这是一个简单的例子

use strict;
use Coro;
use Coro::Socket;
use Coro::Handle;
use Coro::PatchSet;

my @clients;
pipe(my $reader, my $writer);

defined( my $child = fork )
    or die 'fork: ', $!;

if ($child == 0) {
    close $reader;

    sub blocking_receive_function {
        sleep 1;
        return "test\n";
    }

    while (1) {
        my $str = blocking_receive_function();
        syswrite($writer, $str);
    }

    exit;
}

close $writer;
$reader = unblock $reader; # make it Coro aware

async_pool {
    # thread for reading blocking_receive_function results
    # and write it to clients
    while (1) {
        my $line = $reader->readline();

        for (my $i=$#clients; $i>=0; $i--) {
            unless (defined $clients[$i]->syswrite($line)) {
                # some error
                # we need to do smth
                # let's remove this client
                warn "Error on $clients[$i]: $!";
                splice @clients, $i, 1;
            }
        }
    }
}

my $server = Coro::Socket->new(Listen => 1024, LocalPort => 8000)
    or die "Can't create server", $@;

while (1) {
    my $client = $server->accept()
        or next;
    push @clients, $client;
}
于 2013-12-15T06:11:20.570 回答
0

Sharing file descriptors among processes might be too much pain for your task. I came across this problem some time ago and I figured it was better to rethink my approach by using a select() call instead.

However, if you really want to achieve this without dependencies, it is possible to pass file descriptors between processes using Unix sockets configured with the right SOL_SOCKET options via the setsockopt() call.

于 2013-12-15T10:03:01.800 回答