f



"broken pipe" while reading/writing stream-based sockets

Ciao,

I'm still having problems while doing sockets read/write. I have a
server that often crashes with error "Broken Pipe". The server works
always with the same clients and many times it doesn't crash until
something happens that I don't understand.

This is the server code:

-- file tcp_server.adb

with GNAT.Sockets;             use GNAT.Sockets;
with Ada.Text_IO;                use Ada.Text_IO;

procedure TCP_Server is

    Socket : Socket_Type;
    Client : Socket_Type;
    Sock_Addr : Sock_Addr_Type;
    Cli_Addr : Sock_Addr_Type;
    L : constant Positive := 5;
    Channel : Stream_Access;
    S : String( 1 .. 80 );

begin

    Initialize;
    Create_Socket( Socket );
    Set_Socket_Option( Socket, Socket_Level, ( Reuse_Address, True ) );
    Sock_Addr.Addr := Inet_Addr( "127.0.0.1" );
    Sock_Addr.Port := 9876;
    Bind_Socket( Socket, Sock_Addr );
    Listen_Socket( Socket, L );
    Put_Line( "Server in attesa di connessioni..." );

    loop
        Accept_Socket( Socket, Client, Cli_Addr );
        Channel := Stream( Client );
        String'Read( Channel, S );
        String'Write ( Channel, ( "Ricevuto " & S ) );
        Put_Line( "Client ha inviato codice """ & S & """" );
        Free( Channel );
        Close_Socket( Client );
        if S( 1 .. 4 ) = "kill" then
            Put_Line( "Sono stato ucciso" );
            exit;
        end if;
    end loop;

    Close_Socket( Socket );
    Finalize;

end TCP_Server;


And the following is client code:

-- file tcp_client.adb

with GNAT.Sockets;             use GNAT.Sockets;
with Ada.Text_IO;                 use Ada.Text_IO;
with Ada.Strings;                  use Ada.Strings;
with Ada.Strings.Fixed;         use Ada.Strings.Fixed;
with Ada.Command_Line;      use Ada.Command_Line;

procedure TCP_Client is

    Socket : Socket_Type;
    Address : Sock_Addr_Type;
    Channel : Stream_Access;
    S : String( 1 .. 80 );

begin

    if Argument_Count < 1 then
        return;
    end if;

    Initialize;
    Create_Socket( Socket );
    Address.Addr := Addresses( Get_Host_By_Name( "localhost" ), 1 );
    Address.Port := 9876;
    Connect_Socket( Socket, Address );
    Channel := Stream( Socket );

    Move( Argument( 1 ), S );
    if S( 1 .. 4 ) = "kill" then
        Put_Line( "Sto ordinando a Server di fermarsi!" );
    else
        Put_Line( "Sto inviando """ & Trim( S, Both ) & """" );
    end if;

    String'Write( Channel, S );
    String'Read( Channel, S );
    Put_Line( "Server ha risposto """ & Trim( S, Both ) & """" );

    Free( Channel );
    Close_Socket( Socket );
    Finalize;

end TCP_Client;


I usually test the server this way:

$ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz & ./tcp_client
kill

1) Why does this server sometimes crash with "Broken Pipe"?
2) It seems that using Input/Output instead of Read/Write never causes
"Broken Pipe". Why?

Thanks to all of you who will reply,

fabio de francesco

0
fmdf (90)
5/10/2005 11:02:59 PM
comp.lang.ada 8774 articles. 2 followers. Post Follow

10 Replies
1210 Views

Similar Articles

[PageSpeed] 13

fabio de francesco wrote:
> I usually test the server this way:
> 
> $ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz & ./tcp_client
> kill
> 
> 1) Why does this server sometimes crash with "Broken Pipe"?

on my windows machine, i get the windows equivalent ("connection reset 
by peer") on every test.

it seems due to the speed of your computer. i observed that closing a 
local socket (that is a socket which connect a server and a client on 
the same machine) while data are not already received by the other 
side always causes loss of data on fast computers.

-- 
rien
0
5/11/2005 10:46:08 AM
Adrien Plisson wrote:
> fabio de francesco wrote:
> > I usually test the server this way:
> >
> > $ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz &
../tcp_client
> > kill
> >
> > 1) Why does this server sometimes crash with "Broken Pipe"?
>
> on my windows machine, i get the windows equivalent ("connection
reset
> by peer") on every test.

I get the same error as yours on the client side. "Broken Pipe" is only
on server side. We get "connection reset by peer" only after the server
crashes.

>
> it seems due to the speed of your computer. i observed that closing a

> local socket (that is a socket which connect a server and a client on

> the same machine) while data are not already received by the other
> side always causes loss of data on fast computers.
>

I'm not so sure, because I have never seen that "Broken Pipe" error
before now on my computer. Furthermore I don't get any crashes while
running similar client/server Ada programs using T'Input/T'Output or
Receive_Socket/Send_Socket on the same computer.

If it can help in investigating this issue I can post these other
programs too.

As a consequence I must think I am missing something in that specific
code. Please help me to spot what I'm doing wrong.

fabio de francesco

0
fmdf (90)
5/11/2005 3:01:38 PM
"fabio de francesco" <fmdf@tiscali.it> writes:

> I usually test the server this way:
>
> $ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz & ./tcp_client
> kill
>
> 1) Why does this server sometimes crash with "Broken Pipe"?

Just now I replaced your 'kill' above with 'lmn' and ran it 25 times
with no errors -- GCC 4.0.0 on Darwin 7.9.0

--S
0
simon8285 (1465)
5/11/2005 9:18:05 PM
Simon Wright wrote:
> "fabio de francesco" <fmdf@tiscali.it> writes:
>
> > I usually test the server this way:
> >
> > $ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz &
../tcp_client
> > kill
> >
> > 1) Why does this server sometimes crash with "Broken Pipe"?
>
> Just now I replaced your 'kill' above with 'lmn' and ran it 25 times
> with no errors -- GCC 4.0.0 on Darwin 7.9.0
>
> --S

I compiled the program with GCC 3.4.1 on Linux 2.6.11.5. It continues
to report the same error.

I'm going to bootstrap a brand new GCC 4.0 and then I try again.

fabio de francesco

0
fmdf (90)
5/11/2005 11:30:30 PM
Simon Wright wrote:
> "fabio de francesco" <fmdf@tiscali.it> writes:
>
> > I usually test the server this way:
> >
> > $ ./tcp_client abc & ./tcp_client def & ./tcp_client xyz &
../tcp_client
> > kill
> >
> > 1) Why does this server sometimes crash with "Broken Pipe"?
>
> Just now I replaced your 'kill' above with 'lmn' and ran it 25 times
> with no errors -- GCC 4.0.0 on Darwin 7.9.0
>
> --S

As I wrote in a previous message I bootstrapped a new GCC 4.0.0 and
then I recompiled those programs again.

The server program continues to crash giving a more elaborated message:

raised GNAT.SOCKETS.SOCKET_ERROR : [32] Broken pipe

The message I got with GCC 3.4.1 was only "Broken Pipe". Now there's
also that "32" number. What is it?

Do any of you have any suggestion on this problem?

Regards,

fabio de francesco

0
fmdf (90)
5/13/2005 8:18:46 PM
fabio de francesco wrote:

>
> As I wrote in a previous message I bootstrapped a new GCC 4.0.0 and
> then I recompiled those programs again.
>
> The server program continues to crash giving a more elaborated
message:
>
> raised GNAT.SOCKETS.SOCKET_ERROR : [32] Broken pipe
>
> The message I got with GCC 3.4.1 was only "Broken Pipe". Now there's
> also that "32" number. What is it?
>
> Do any of you have any suggestion on this problem?
>

Where and how would you generally investigate on a problem like this?

fdf

0
fmdf (90)
5/13/2005 8:25:01 PM
fabio de francesco wrote:

> raised GNAT.SOCKETS.SOCKET_ERROR : [32] Broken pipe

One thing you could do is handle Gnat.Sockets.Socket_Error.

-- 
Jeff Carter
"There's no messiah here. There's a mess all right, but no messiah."
Monty Python's Life of Brian
84
0
spam29 (1568)
5/14/2005 8:39:16 PM
* fabio de francesco:

> 1) Why does this server sometimes crash with "Broken Pipe"?

This usually indicates that the client closed its end of the
connection while the server was still sending data.  Maybe this
happens because your code does not deal with partial reads/writes.

> 2) It seems that using Input/Output instead of Read/Write never causes
> "Broken Pipe". Why?

The stream implementation provided by GNAT.Sockets deals with partial
reads and writes.
0
fw12 (438)
5/14/2005 9:27:16 PM
Florian Weimer wrote:
> * fabio de francesco:
>
> > 1) Why does this server sometimes crash with "Broken Pipe"?
>
> This usually indicates that the client closed its end of the
> connection while the server was still sending data.  Maybe this
> happens because your code does not deal with partial reads/writes.
>
> > 2) It seems that using Input/Output instead of Read/Write never
causes
> > "Broken Pipe". Why?
>
> The stream implementation provided by GNAT.Sockets deals with partial
> reads and writes.

In C I know how to read() in a loop and increment a pointer to a buffer
(a C string) while receiving characters until there are no more of
them. It is sufficient that read() returns how many characters has
already read and some little math involving buffer size.

In Ada I don't know how to do it... Can you please give me any
suggestions?

Thank you in advance.

fabio

0
fmdf (90)
5/20/2005 3:01:28 PM
"fabio de francesco" <fmdf@tiscali.it> writes:

> Florian Weimer wrote:
>> * fabio de francesco:
>>
>> > 1) Why does this server sometimes crash with "Broken Pipe"?
>>
>> This usually indicates that the client closed its end of the
>> connection while the server was still sending data.  Maybe this
>> happens because your code does not deal with partial reads/writes.
>>
>> > 2) It seems that using Input/Output instead of Read/Write never
> causes
>> > "Broken Pipe". Why?
>>
>> The stream implementation provided by GNAT.Sockets deals with partial
>> reads and writes.
>
> In C I know how to read() in a loop and increment a pointer to a buffer
> (a C string) while receiving characters until there are no more of
> them. It is sufficient that read() returns how many characters has
> already read and some little math involving buffer size.
>
> In Ada I don't know how to do it... Can you please give me any
> suggestions?

I'm sure there's a better way .. but this is what I did

   function Read_Request (From : Socket_Type) return String is
      Tmp : Stream_Element_Array (1 .. 2048);
      Last : Stream_Element_Offset := Tmp'First - 1;
      Next : Stream_Element_Offset;
      Termination : constant Stream_Element_Array :=
        (Character'Pos (CR),
         Character'Pos (LF),
         Character'Pos (CR),
         Character'Pos (LF));
      S : Stream_Access := Stream (From);
   begin

      --  We need to read the whole request from the client. Of course
      --  we don't know how long it is. We can't just issue an
      --  Ada.Streams.Read for a large buffer, because the client may
      --  not have sent that much and if she hasn't we'll block until
      --  she gives up and closes the socket. So we read a character
      --  at a time until we've got the CR/LF/CR/LF which terminates
      --  the line.
      loop
         Ada.Streams.Read (Stream => S.all,
                           Item => Tmp (Last + 1 .. Last + 1),
                           Last => Next);
         exit when Next = Last;
         Last := Last + 1;
         exit when Last >= Termination'Length
           and then Tmp (Last - 3 .. Last) = Termination;
         exit when Last = Tmp'Last;
      end loop;

      Free_Stream (S);

      declare
         Result : String (1 .. Natural (Last));
         pragma Import (Ada, Result);
         for Result'Address use Tmp'Address;
      begin
         return Result;
      end;

   end Read_Request;
0
simon8285 (1465)
5/20/2005 8:02:49 PM
Reply: