在启用BLOCKING的情况下刷新INET套接字响应数据

时间:2014-07-14 05:16:57

标签: perl sockets

我正在创建一个与Teamspeak接口的程序,我遇到的问题是收到的响应与发送的命令不匹配。我多次运行该程序,每次都会得到不同的结果,因为响应不同步。

my $buf = '';
use IO::Socket; 
my $sock = new IO::Socket::INET (
    PeerAddr => 'localhost'
    ,PeerPort => '10011'
    ,Proto => 'tcp'
    ,Autoflush   => 1
    ,Blocking    => 1
    ,Timeout    => 10
    ); 

sub ExecuteCommand{
    print $sock $_[0]."\n";$sock->sysread($buf,1024*10);
    return $buf;
};

ExecuteCommand("login ${username} ${password}");
ExecuteCommand("use sid=1");
ExecuteCommand("clientupdate client_nickname=Idle\\sTimer");
my $client_list = ExecuteCommand("clientlist");

每个命令都正确执行,但服务器喜欢返回额外的行,因此单个sysread将不够,我将不得不执行另一个。响应的大小最多为512,因此它们不会被切断。如果我尝试多次运行sysread以尝试刷新它,当没有任何内容可读时它只会让程序挂起。

执行结束之后是“error id = 0 msg = ok”

我怎样才能读出所有出来的数据,即使它是多行?或者只是能够将它全部冲洗掉,这样我就可以移动到下一个命令而不必担心旧数据?

2 个答案:

答案 0 :(得分:0)

所以你要阅读,直到找到以error开头的行。除此之外,以下缓冲任何额外的读取,因为它是下一个响应的一部分。

sub read_response {
   my ($conn) = @_;

   my $fh               =   $conn->{fh};
   our $buf; local *buf = \($conn->{buf});  # alias
   our $eof; local *eof = \($conn->{eof});  # alias

   $buf = '' if !defined($buf);

   return undef if $eof;

   while (1) {
      if ($buf =~ s/\A(.*?^error[^\n]*\n)//ms) {
         return $1;
      }

      my $rv = sysread($fh, $buf, 64*1024, length($buf));
      if (!$rv) {
         if (defined($rv)) {
            $eof = 1;
            return undef;
         } else {
            die "Can't read response: $!\n";
         }
      }
   }
}

my $conn = { fh => $sock };

... send command ...
my $response = read_response($conn);
...

... send command ...
my $response = read_response($conn);
...

答案 1 :(得分:0)

我更改了我的ExecuteCommand子例程以包含对“错误代码= [0-9] {1,}”的检查,这是Teamspeak 3服务器响应结束时的总是。

sub ExecuteCommand{
    print $sock $_[0]."\n";
    my $response = "";
    while (1){
        $sock->sysread($buf,1024*10);
        last if($buf =~ /error id=([0-9]{1,})/);
        $response .= $buf;
    };
    return $response;
};