【问题标题】:Flush INET Socket response data with BLOCKING enabled在启用 BLOCKING 的情况下刷新 INET 套接字响应数据
【发布时间】:2014-07-14 05:16:56
【问题描述】:

我正在制作一个与 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”

我如何能够读取所有输出的数据,即使它是多行的?或者只是能够将其全部清除,以便我可以继续执行下一个命令而不必担心旧数据?

【问题讨论】:

  • 我正在运行一个循环,从 clientlist 生成的列表中检查每个客户端,但我得到了不属于列表的内容。所以如果我print ExecuteCommand("clientinfo clid=1"),然后是print ExecuteCommand("clientinfo clid=2"),我将得到“错误代码=0”,而不是获取客户端信息。如果我然后运行 ​​$sock->sysread($buf,1024*10);print $buf; 我将从 clid=2 获取客户端信息

标签: perl sockets


【解决方案1】:

因此,您要一直阅读,直到找到以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);
...

【讨论】:

  • 我做对了吗? sub ExecuteCommand{ print $sock $_[0]."\n";return read_response($conn);}; 因为现在它挂起,就像我尝试读取不存在的响应时一样(由于 Blocking = 1)。
  • 哦,我将错误匹配更改为$buf =~ /error id=([0-9]{1,})/i,它可以工作。但是,我现在的回答只是零。
  • 哈哈我刚刚理解你的代码,我把它改回原来的样子。但是在它第一次执行后我仍然遇到了问题。
  • 啊,我以为错误出现在一行的开头。如果不是,请删除^
【解决方案2】:

我更改了我的 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;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多