splice() 从管道到 TCP 缓冲?
来自 linuxquestions.org 的 xpost,抱歉...
我编写了一个小测试程序,看看简单的代理是否会从使用 splice() 中受益,但读取我从管道拼接到 TCP 套接字的数据总是需要 200 毫秒从插座的另一端。
下面是用于测试它的 Perl 程序:
package test_pipes_2;
use strict;
use warnings;
use IO::Handle();
use POSIX qw(:errno_h);
use Time::HiRes qw(time);
use English qw(-no_match_vars);
use IO::Socket::INET;
use Socket qw(IPPROTO_TCP TCP_NODELAY);
__PACKAGE__->run if not caller;
sub run {
my( $class ) = @ARG;
pipe my $parent_reader, my $child_writer;
my $parent_reader_fd = fileno $parent_reader;
my $child_writer_fd = fileno $child_writer;
pipe my $child_reader, my $parent_writer;
my $child_reader_fd = fileno $child_reader;
my $parent_writer_fd = fileno $parent_writer;
my $server = IO::Socket::INET->new(
LocalAddr => '127.0.0.1:9000',
Type => SOCK_STREAM,
Listen => 5,
ReuseAddr => 1,
Blocking => 1,
) || die $OS_ERROR;
my $client_browser = IO::Socket::INET->new(
PeerAddr => '127.0.0.1:9000',
Type => SOCK_STREAM,
Blocking => 1,
) || die $OS_ERROR;
# setsockopt $client_browser, IPPROTO_TCP, TCP_NODELAY, 1;
my $client_browser_fd = fileno $client_browser;
my $server_browser = $server->accept() || die $OS_ERROR;
# setsockopt $server_browser, IPPROTO_TCP, TCP_NODELAY, 1;
my $server_browser_fd = fileno $server_browser;
for( 1 .. 3 ) { # 100_000
syswrite $client_browser, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n";
$server_browser->recv( my $request1, 4096, POSIX::MSG_PEEK );
syscall 313, $server_browser_fd, undef, $child_writer_fd, undef, 4096, 1;
sysread $parent_reader, my $request2, 4096;
my $response = "200 OK\n<head><title>html</title></head><body>body from $PID</body>";
syswrite $parent_writer, $response;
syscall 313, $child_reader_fd, undef, $server_browser_fd, undef, 4096, 1;
# syswrite $server_browser, "\n"; # eliminates delay, adds syscall...
sysread $client_browser, my $response1, 4096;
# chomp $response1;
if( $response1 ne $response ) {
warn 'Got wrong response: ', $response1 // 'undef';
no warnings 'once';
$DB::single = 1;
}
}
}
1;
下面是 strace 输出的示例:
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 8 <0.000010>
setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 <0.000006>
bind(8, {sa_family=AF_INET, sin_port=htons(9000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 <0.000008>
listen(8, 5) = 0 <0.000008>
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 9 <0.000006>
connect(9, {sa_family=AF_INET, sin_port=htons(9000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 <0.000037>
accept(8, {sa_family=AF_INET, sin_port=htons(49361), sin_addr=inet_addr("127.0.0.1")}, [16]) = 10 <0.000007>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000014>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000007>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000007>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000007>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200331>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000016>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000008>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000006>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000006>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200622>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000018>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000007>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000006>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000005>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200649
请注意大约 200 毫秒的 read(9,...) 调用。如果我取消注释该行以发送“\n”,则不会有延迟。我做错了什么?谢谢!
xpost from linuxquestions.org, sorry...
I wrote a small test program to see if a simple proxy would benefit from using splice() but it always takes 200ms for the data that I spliced from a pipe to a TCP socket to be read from the other end of the socket.
Here is the Perl program to test it:
package test_pipes_2;
use strict;
use warnings;
use IO::Handle();
use POSIX qw(:errno_h);
use Time::HiRes qw(time);
use English qw(-no_match_vars);
use IO::Socket::INET;
use Socket qw(IPPROTO_TCP TCP_NODELAY);
__PACKAGE__->run if not caller;
sub run {
my( $class ) = @ARG;
pipe my $parent_reader, my $child_writer;
my $parent_reader_fd = fileno $parent_reader;
my $child_writer_fd = fileno $child_writer;
pipe my $child_reader, my $parent_writer;
my $child_reader_fd = fileno $child_reader;
my $parent_writer_fd = fileno $parent_writer;
my $server = IO::Socket::INET->new(
LocalAddr => '127.0.0.1:9000',
Type => SOCK_STREAM,
Listen => 5,
ReuseAddr => 1,
Blocking => 1,
) || die $OS_ERROR;
my $client_browser = IO::Socket::INET->new(
PeerAddr => '127.0.0.1:9000',
Type => SOCK_STREAM,
Blocking => 1,
) || die $OS_ERROR;
# setsockopt $client_browser, IPPROTO_TCP, TCP_NODELAY, 1;
my $client_browser_fd = fileno $client_browser;
my $server_browser = $server->accept() || die $OS_ERROR;
# setsockopt $server_browser, IPPROTO_TCP, TCP_NODELAY, 1;
my $server_browser_fd = fileno $server_browser;
for( 1 .. 3 ) { # 100_000
syswrite $client_browser, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n";
$server_browser->recv( my $request1, 4096, POSIX::MSG_PEEK );
syscall 313, $server_browser_fd, undef, $child_writer_fd, undef, 4096, 1;
sysread $parent_reader, my $request2, 4096;
my $response = "200 OK\n<head><title>html</title></head><body>body from $PID</body>";
syswrite $parent_writer, $response;
syscall 313, $child_reader_fd, undef, $server_browser_fd, undef, 4096, 1;
# syswrite $server_browser, "\n"; # eliminates delay, adds syscall...
sysread $client_browser, my $response1, 4096;
# chomp $response1;
if( $response1 ne $response ) {
warn 'Got wrong response: ', $response1 // 'undef';
no warnings 'once';
$DB::single = 1;
}
}
}
1;
And here is a sample of the strace output:
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 8 <0.000010>
setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 <0.000006>
bind(8, {sa_family=AF_INET, sin_port=htons(9000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 <0.000008>
listen(8, 5) = 0 <0.000008>
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 9 <0.000006>
connect(9, {sa_family=AF_INET, sin_port=htons(9000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 <0.000037>
accept(8, {sa_family=AF_INET, sin_port=htons(49361), sin_addr=inet_addr("127.0.0.1")}, [16]) = 10 <0.000007>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000014>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000007>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000007>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000007>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200331>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000016>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000008>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000006>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000006>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200622>
write(9, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 41) = 41 <0.000018>
recvfrom(10, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096, MSG_PEEK, {sa_family=0x8b60 /* AF_??? */, sa_data="(\10\2\0\300\321\177\0\0\1\0\0\0\0"...}, [0]) = 41 <0.000007>
splice(0xa, 0, 0x5, 0, 0x1000, 0x1) = 41 <0.000006>
read(4, "HTTP/1.1 GET /foo/\r\nLocation: foo.com\r\n\r\n"..., 4096) = 41 <0.000005>
write(7, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 67) = 67 <0.000005>
splice(0x6, 0, 0xa, 0, 0x1000, 0x1) = 67 <0.000005>
read(9, "200 OK\n<head><title>html</title></head><body>body from 14019</body>"..., 4096) = 67 <0.200649
Note the ~200ms read(9,...) calls. If I uncomment the line to send a "\n" then there is no delay. What am I doing wrong? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论