Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

661 views
Skip to first unread message

fabio de francesco

unread,
May 10, 2005, 7:02:59 PM5/10/05
to
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

Adrien Plisson

unread,
May 11, 2005, 6:46:08 AM5/11/05
to
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

fabio de francesco

unread,
May 11, 2005, 11:01:38 AM5/11/05
to

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

Simon Wright

unread,
May 11, 2005, 5:18:05 PM5/11/05
to
"fabio de francesco" <fm...@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

fabio de francesco

unread,
May 11, 2005, 7:30:30 PM5/11/05
to

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

fabio de francesco

unread,
May 13, 2005, 4:18:46 PM5/13/05
to

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

fabio de francesco

unread,
May 13, 2005, 4:25:01 PM5/13/05
to

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

Jeffrey Carter

unread,
May 14, 2005, 4:39:16 PM5/14/05
to
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

Florian Weimer

unread,
May 14, 2005, 5:27:16 PM5/14/05
to
* 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.

fabio de francesco

unread,
May 20, 2005, 11:01:28 AM5/20/05
to

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

tmo...@acm.org

unread,
May 20, 2005, 1:52:22 PM5/20/05
to
> 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?
Buffer : String(a .. b);
Last : Natural := Buffer'first-1;
begin
while Last < Buffer'last loop
read(input_source, Buffer(Last+1 .. Buffer'last), Last);
end loop;

Simon Wright

unread,
May 20, 2005, 4:02:49 PM5/20/05
to
"fabio de francesco" <fm...@tiscali.it> writes:

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 new messages