in reply to HTTP::Daemon and broken pipes

A HTTP server needs to ignore SIGPIPE. Otherwise the server might die just because a client got closed before it finished reading the response from the server (though I thought that TCP/IP sockets didn't signal SIGPIPE -- but it probably varies by operating system).

If a client goes away, it could take a while for the server's attempt to send data to it to eventually fail. It depends how the client goes away. If the client process dies, then the operating system will usually ensure that the send attempts quickly fail. If the client hangs, the computer or network fails, or many other failure cases, then the server is likely to be tied up for about 2 minutes trying to decide whether to give up resending data.

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: (tye)Re: HTTP::Daemon and broken pipes
by dash2 (Hermit) on Feb 18, 2002 at 19:37 UTC

    Thanks Tye.

    Actually, I am testing over the local loopback, so this may explain the SIGPIPEs. But assume I do ignore SIGPIPE, I still wonder how to stop getting continual "could not connect errors". I remember IO::Socket has a listen method... can I call this on HTTP::Daemon to allow it to queue connections? I'll try it.

    dave hj~

Re: (tye)Re: HTTP::Daemon and broken pipes
by dash2 (Hermit) on Feb 18, 2002 at 22:26 UTC
    My idea of setting listen() didn't work. I have experimented some more. Essentially, the system works fine for a bit, but then starts receiving SIGPIPEs. After that, nothing gets through... for some reason the message receiver never manages to accept another message. Here is my current code - can anyone see what I am doing wrong?

    sub accept_messages { my $self = shift; unless ($self->{daemon}) { my ($localaddr, $localport) = split /:/, $self->{address}; $self->{daemon} = new HTTP::Daemon ( LocalAddr => $localaddr, LocalPort => $localport ); ref $self->{daemon} or $self->_debug("Could not create HTTP::Daemon +$! $@", 3); $self->{daemon}->timeout($self->{timeout}) if $self->{timeout}; $self->{daemon}->listen($self->{queue}) if $self->{queue}; # tried s +etting this to 15. no joy. } local $SIG{PIPE} = sub { $self->_debug('PIPE WHILE ACCEPTING MESSAGE'); }; CONNECTION: while (1) { my $conn = $self->{daemon}->accept; # blocks return undef unless $conn; my $req = $conn->get_request; unless ($req) { $self->_debug( 'Problem reading from connection: ' . $conn->reason ); next CONNECTION; } if ($req->method ne 'POST') { my $r = new HTTP::Response (405,'POST method only' ); $conn->send_response($r); $conn->close; next CONNECTION; } elsif (my $content = $req->content) { my $r = new HTTP::Response(200, 'OK'); $conn->send_response($r); $conn->close; return $content; } } } sub transport_message { my $self = shift; my $message_string = shift; my $peer = shift; my $headers = new HTTP::Headers; $headers->date(time); $headers->content_type('text/plain'); $headers->server('Net::Distributed'); my $request = new HTTP::Request ( 'POST', "http://" . $peer->address, $headers, $message_string ); unless ($self->{UserAgent}) { $self->{UserAgent} = new LWP::UserAgent; $self->{UserAgent}->agent ("Net::Distributed::Transport/$VERSION"); $self->{UserAgent}->from ($self->{email}); $self->{UserAgent}->parse_head(0); $self->{UserAgent}->timeout($self->{send_timeout}); } my $ua = $self->{UserAgent}; local $SIG{PIPE} = sub { $self->_debug('PIPE WHILE SENDING MESSAGE'); }; my $response = $ua->request($request); if ($response->is_success) { return 1; # of course, there may be problems further down the line } else { $self->_debug("Got " . $response->status_line . " from " . $peer->ad +dress, 0); return 0; } }
    dave hj~