splice()从管道到TCP缓冲?

时间:2010-09-22 01:39:18

标签: tcp linux-kernel pipe splice zero-copy

来自linuxquestions.org的xpost,抱歉......

我编写了一个小的测试程序来查看一个简单的代理是否会从使用splice()中受益,但是从管道拼接到TCP套接字的数据总是需要200ms才能从套接字的另一端读取

以下是测试它的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

注意~200ms读取(9,...)调用。如果我取消注释该行以发送“\ n”,则没有延迟。我究竟做错了什么?谢谢!

0 个答案:

没有答案