できるだけ早くUnixソケットファイルに書き込む

できるだけ早くUnixソケットファイルに書き込む

Perlを使用してできるだけ早くUnixソケットファイルに書き込もうとしますが、メッセージバッファ全体で失敗します。自動リフレッシュと手動リフレッシュを試みましたが、成功しませんでした。

use IO::Select;
use IO::Socket::UNIX;

my $sock = IO::Socket::UNIX->new(
    Type => IO::Socket::SOCK_DGRAM,
    Peer => "/dev/log",
) or die "$!\n";
$sock->autoflush(1);  
my $sel = IO::Select->new($sock);
my $cnt = 0;
while(<>){
    $sel->can_write or die "1 line $cnt: $!\n";             
    $sock->say($_) or die "2 line $cnt: $!\n"; 
    $sock->flush or die "3 line $cnt: $!\n";
    $cnt++;
}
$sock->close();

出力は常に2 line 64: No buffer space available

アップデート:私はPerlを使うつもりはありません。おそらく、IBM AIXのソケットに送信するより良い方法があるかもしれません。

答え1

観察されたように、すでにいっぱいのネット​​ワークスタックにより多くのデータをより速く転送しようとすることは機能しません。少なくとも、すでにいっぱいのバスルームの排水口に多くのデータを注ぐよりも簡単です。それにもかかわらず、ここで送信者は条件が解決されるまで待たなければなりません。それ以外の場合は、ネットワークスタックのバッファが大きくなって処理されるまで、データは他の場所(たとえばカーネルの浄化槽)にプールされます。また、データグラムはフラッシュするストリームがあるかどうかを実際には知らず、$.Perl変数はすでにアクションを実行している$cntため

#!/usr/bin/env perl
use strict;
use warnings;
use Errno ':POSIX';
use IO::Socket::UNIX;
use Time::HiRes 'usleep';

my $peer = shift || die "Usage: $0 /dev/log\n";

my $sock = IO::Socket::UNIX->new(
    Peer => $peer,
    Type => IO::Socket::SOCK_DGRAM,
) or die "socket failed '$peer': $!\n";

LINE: while (<>) {
    $sock->print($_) and next;
    if ($!{ENOBUFS}) {
        while (1) {
            # exponential backoff might be more typical and less rude
            # here, or the code could try to be smart about how long to
            # wait for, but that takes more code and more memory and
            # more effort on the part of the programmer
            usleep(128);
            $sock->print($_) and last;
            # PORTABILITY and there may be a bunch of different error
            # messages from trying to go too fast here with a full
            # buffer, check for them ...
            unless ($!{EMSGSIZE} or $!{ENOBUFS} or $!{ETIMEDOUT}) {
                my $errno = 0 + $!;
                die "print failed line $.: $! ($errno)";
            }
        }
    } else {
        my $errno = 0 + $!;
        die "print failed line $.: $! ($errno)";
    }
}

関連情報