我有一个守护进程,它接受连接、通过单个 sysread 读取 JSON 请求、处理它并通过 syswrite 发回 JSON 响应。这工作正常。但我想让阅读在部分阅读的情况下更加健壮。所以我使用了常见的技术,我看到人们使用循环直到读取 0 个字节,同时指定将输入附加到缓冲区的末尾。当我执行这个简单的循环时,以下 syswrite 声称它写出了 X 个字节,但调用者认为它读回了 0 个字节。似乎在套接字上执行 1 次以上的 sysread 会导致 future 对该套接字的 syswrite 失败。
即:我已经更改了我的单个 sysread 来执行此操作:
my $done = 0 ;
while ( ! $done ) {
$bytes = sysread( $client, $json_text, BUFSIZ, length( $json_text )) ;
$done++ if ( $bytes == 0 ) ;
}
我已经验证在每种情况下,我收到的请求是相同的,我发送的响应是相同的。唯一改变的是额外的 sysread,它读取了 0 个字节,表明我已经阅读了所有可用的内容。
我附上了一个简单的精简程序来说明这一点。
有人可以向我解释这里发生了什么吗?
我还尝试专门告诉 syswrite 要写入的字节数和起始位置 (0),效果相同。
#!/usr/bin/env perl
use Socket ;
use JSON ;
use constant BUFSIZ => 1024 ;
my $protocol = getprotobyname( 'tcp' ) ;
my $server ;
if ( ! socket( $server, AF_INET, SOCK_STREAM, $protocol )) {
die( "socket() failed: $!" ) ;
}
if ( ! setsockopt( $server, SOL_SOCKET, SO_REUSEADDR, 1 )) {
die( "setsockopt(): failed: $!" ) ;
}
my $my_addr = sockaddr_in( 2007, INADDR_ANY ) ;
bind( $server, $my_addr ) or die( "bind(): failed: $!" ) ;
listen( $server, SOMAXCONN ) or die( "listen(): failed: $!" ) ;
my ( $remote_addr, $client ) ;
$remote_addr = accept( $client, $server ) ;
$_ = select( $client ); $| = 1; select $_ ; # autoflushing
my $json_text = "" ;
my $bytes = 0 ;
# a later syswrite() doesn't work when sysread() called more than once
my $done = 0 ;
while ( ! $done ) {
$bytes = sysread( $client, $json_text, BUFSIZ, length( $json_text )) ;
$done++ if ( $bytes == 0 ) ;
}
# calling sysread once works ok with following syswrite
# sysread( $client, $json_text, BUFSIZ, length( $json_text )) ;
print "Got a JSON request: $json_text\n" ;
# just make up some dummy response to whatever we received
my $out_struct = {
'id' => 'server6-alive-test',
'output' => [ 'FOOBAR' ],
'errors' => [],
'status' => 0,
'served-by' => 'server6',
};
$json_text = to_json( $out_struct, { utf8 => 1, pretty => 1 } ) ;
my $num = syswrite( $client, $json_text ) ;
print "wrote $num bytes to server\n" ;
这个调试输出是从调用者的角度来看的:
# NO while loop
debug: main::set_up_systems: testing if server6 is alive
debug: main::send_cmd_to_daemon: sending command 'alive' to remote
debug: main::check_if_system_alive: Got: 'FOOBAR'
# with while loop version
debug: main::set_up_systems: testing if server6 is alive
debug: main::send_cmd_to_daemon: sending command 'alive' to remote
debug: main::send_cmd_to_daemon: empty JSON string returned
debug: main::process_cmd: server6: No output sent back.
最佳答案
你说守护进程中的 syswrite
失败了,但你也说它返回了一个正数。这表明它没有失败。 syswrite
出错时返回 undef
。
守护进程中的 sysread
循环会一直读取,直到遇到 EOF,此时 sysread
返回 0
。我猜测客户端通过关闭整个套接字来发出 EOF 信号,导致客户端中的 sysread
失败(返回 undef
并将 $!
设置为 EBADF
(错误的文件描述符))。相反,只使用一半关闭编写器
use Socket qw( SHUT_WR );
shutdown($sock, SHUT_WR)
or die($!);
关于perl - 多个 sysreads 导致以下 syswrite 在 Perl 中失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41463996/