comp.lang.ada
 help / color / mirror / Atom feed
* TCP/IP Sockets with GNAT.Sockets
@ 2005-05-02  2:42 fabio de francesco
  2005-05-02  5:58 ` Eric Jacoboni
  2005-05-02 12:11 ` Adrien Plisson
  0 siblings, 2 replies; 23+ messages in thread
From: fabio de francesco @ 2005-05-02  2:42 UTC (permalink / raw)


Hello,

Today is the first time I try to use sockets in Ada programs, even if I
have some practical knowledge of programming with TCP/IP sockets in C.
Because I didn't find any better tutorial on working with GNAT.Sockets
I am relying on comments in file g-socket.ads from GCC/GNAT sources
where there is not a complete and detailed coverage of the subject.

(1) Do you know any better tutorial?

Then I wrote two little programs in order to try the package. A server
waits for connections and a client sends a string and receive an echo
from the first one. The client can also shutdown the server by sending
a predefined string.

I hadn't too many problems with exchanging messages and everything
works. The problem is that I was only able to use Streams for
communicating between them and I can't understand at all how to use
Receive_Socket() and Send_Socket() because they use
"Stream_Element_Array" and "Stream_Element _Offset" in place of
Strings. I know that by using Streams they can't communicate with C
programs and I've read that Streams are everything but efficient.

(2) The following is an extract from the client program. It compiles
and works as it is. May you please explain how to modify it in order to
use the above-mentioned functions in place of Input() and Output()? If
the problem can be solved by copying Strings to Stream_Element_Array
and back, how can I do that?

-- file client.adb

with GNAT.Sockets, Ada.Text_IO,
Ada.Strings.Unbounded, Ada.Command_Line;
use GNAT.Sockets, Ada.Text_IO,
Ada.Strings.Unbounded, Ada.Command_Line;

procedure Client is

    Socket : Socket_Type;
    Address : Sock_Addr_Type;
    Channel : Stream_Access;
    Reply : Unbounded_String;

begin

    Initialize;
    Create_Socket( Socket );
    Address.Addr := Inet_Addr( "127.0.0.1" );
    Address.Port := 9876;
    Connect_Socket( Socket, Address );
    Channel := Stream( Socket );

    if Argument_Count > 0 then
        if Argument(1) = "kill" then
            Put_Line( "asking server to shutdown" );
            String'Output( Channel, "kill" );
        else
            Put_Line( "sending """ & Argument( 1 ) & """" );
            String'Output( Channel, Argument( 1 ) );
        end if;
        Reply := Unbounded_String'Input( Channel );
        Put_Line( "server echos """ & To_String( Reply ) & """" );
    end if;

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

end Client;

-- end of client.adb

Thanks to all of you who will reply.

fabio de francesco




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02  2:42 TCP/IP Sockets with GNAT.Sockets fabio de francesco
@ 2005-05-02  5:58 ` Eric Jacoboni
  2005-05-02 12:11 ` Adrien Plisson
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Jacoboni @ 2005-05-02  5:58 UTC (permalink / raw)


In article <1115001752.291144.218410@z14g2000cwz.googlegroups.com>,
fabio de francesco <fmdf@tiscali.it> wrote:

> I hadn't too many problems with exchanging messages and everything
> works. The problem is that I was only able to use Streams for
> communicating between them and I can't understand at all how to use
> Receive_Socket() and Send_Socket() because they use
> "Stream_Element_Array" and "Stream_Element _Offset" in place of
> Strings. I know that by using Streams they can't communicate with C
> programs and I've read that Streams are everything but efficient.

Streams are ok if you manage both the server and the client program.
Otherwise, for talking to a server already written, send and receive
are ok.

> (2) The following is an extract from the client program. It compiles
> and works as it is. May you please explain how to modify it in order to
> use the above-mentioned functions in place of Input() and Output()? If
> the problem can be solved by copying Strings to Stream_Element_Array
> and back, how can I do that?

Here is a simple test code that use send/receive to talk to a POP3
server :

with Gnat.Sockets;     use Gnat.Sockets;
with Ada.Text_Io;      use Ada.Text_Io;
with Ada.Exceptions;   use Ada.Exceptions;
with Ada.Streams;      use Ada.Streams;
with Ada.Command_Line; use Ada.Command_Line;

procedure GetPop3 is

   -- Constantes globales
   BUFSIZ : constant := 256;
   PORT_DEFAUT : constant Port_Type := 110;  
   Protocol_Error : exception;

   -- Wrapper pour Send_Socket
   procedure Send(Sock : in Socket_Type; S : in String) is
      subtype SEA is Stream_Element_Array(1..S'Length);
      My_SEA : SEA;
      for My_SEA'Address use S(S'First)'Address;
      Trash : Stream_Element_Offset;
   begin
      Send_Socket(Sock, My_Sea, Trash);
   end Send;
   
   -- Wrapper pour Receive_Socket
   procedure Receive(Sock : in Socket_Type; S : out String; 
                     Taille : out Natural) is
      subtype SEA is Stream_Element_Array(1..S'Length);
      My_SEA : SEA;
      for My_SEA'Address use S(S'First)'Address;
      Trash : Stream_Element_Offset;
   begin
      Receive_Socket(Sock, My_Sea, Trash);
      Taille := Natural(Trash);
   end Receive;
   
   function Get_Reponse (Sock : Socket_Type) return String is
      Tampon : String(1..BUFSIZ);
      Dernier : Natural;
   begin
      Receive(Sock, Tampon, Dernier);
      return Tampon(1..Dernier); 
   end Get_Reponse ;

   procedure Is_Ok (Reponse : in String) is
   begin
      if Reponse(1..3) /= "+OK" then
         raise Protocol_Error;
      end if;
   end Is_Ok;

   procedure Connexion (Sock : out Socket_Type;
                        Serveur, User, Pass : in String;
                        Port : in Port_Type := PORT_DEFAUT) is
      Adresse : Sock_Addr_Type;
   begin
      -- Construction de l'adresse
     Adresse.Addr := Addresses(Get_Host_By_Name (Serveur));
     Adresse.Port := PORT_DEFAUT;

     -- Creation et connexion de la socket � l'adresse
     Initialize;
     Create_Socket(Sock);           
     Connect_Socket(Sock, Adresse);

     Is_Ok(Get_Reponse(Sock));
     Send(Sock, "user " & User & ASCII.CR & ASCII.LF);
     Is_Ok(Get_Reponse(Sock));
     Send(Sock, "pass " & Pass & ASCII.CR & ASCII.LF);
     Is_Ok(Get_Reponse(Sock));
   end Connexion;

   procedure Commande (Sock : in Socket_Type;
                       Cde  : in String) is
   begin
      Send(Sock, Cde & ASCII.CR & ASCII.LF);
   end Commande;
   
   Sock : Socket_Type;

begin   -- Prog principal
   if Argument_Count /= 3 then
      Put_Line("Usage: " & Command_Name & " <serveur> <user>
<password>");
   else
      begin
         Connexion(Sock, Argument(1), Argument(2), Argument(3));
         Put_Line("Connexion ok");
         Commande(Sock, "stat");
         Put_Line(Get_Reponse(Sock));
         Close_Socket(Sock);
      exception
    when Protocol_Error =>
       Put_Line(Current_Error, "Requete incorrecte");
         when E: others =>
            Put_Line(Exception_Name(E) & ": " & Exception_Message(E));
      end;
   end if;
end GetPop3;



Hope this helps,

-- 
jaco



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02  2:42 TCP/IP Sockets with GNAT.Sockets fabio de francesco
  2005-05-02  5:58 ` Eric Jacoboni
@ 2005-05-02 12:11 ` Adrien Plisson
  2005-05-02 14:55   ` fabio de francesco
  1 sibling, 1 reply; 23+ messages in thread
From: Adrien Plisson @ 2005-05-02 12:11 UTC (permalink / raw)


fabio de francesco wrote:
> Hello,

hello !

> Today is the first time I try to use sockets in Ada programs, even if I
> have some practical knowledge of programming with TCP/IP sockets in C.
> Because I didn't find any better tutorial on working with GNAT.Sockets
> I am relying on comments in file g-socket.ads from GCC/GNAT sources
> where there is not a complete and detailed coverage of the subject.
> 
> (1) Do you know any better tutorial?

personnally, no. the GNAT reference manual says:
"The chapter here simply gives a brief summary of the facilities 
available. The full documentation is found in the spec file for the 
package. The full sources of these library packages, including both 
spec and body, are provided with all GNAT releases."

so, you can rely on the comments in g-socket.ads (which contains some 
full examples). also, the behavior is identical to other sockets 
implementation (C, Python, or others) so don't hesitate to read 
manuals for other languages.

the only big difference is in Streams, which is Ada specific...

[...]
> I hadn't too many problems with exchanging messages and everything
> works. The problem is that I was only able to use Streams for
> communicating between them and I can't understand at all how to use
> Receive_Socket() and Send_Socket() because they use
> "Stream_Element_Array" and "Stream_Element _Offset" in place of
> Strings. I know that by using Streams they can't communicate with C
> programs and I've read that Streams are everything but efficient.

streams are not specially inefficient (to the contrary, my dear). the 
problem is that many people do not clearly understand them !

so let's explain Ada streams:

streams are defined as a tagged record in Ada.Streams, which is to be 
derived in order to implement stream specific behavior: how to send or 
receive data from stream. Streams define 2 procedures for reading and 
writing data onto them. on this side of streams, data are represented 
as Stream_Element grouped in Stream_Element_Array. a single 
Stream_Element may represent a byte you send over the network for 
example.

at this end of streams, there is no data type: what is important is 
the type of streams you manipulate.

on the other end, you are concerned with data types you read from or 
write to stream, but not with the type of streams. on this end, every 
streams are equal, may it be file, socket, or anything else. this is 
achieved through stream oriented attributes: 'Read, 'Write, 'Input and 
'Output. those attributes allow you to read or write a specific data 
type from/to a stream. for example: Integer'Input( S ) will read an 
integer from the stream S (whatever stream type S is). the behavior of 
those attribute may be overriden through an attribute definition clause.

at this end of streams, there is no stream type: what is important is 
the type of data you manipulate.

in fact, stream attributes are kind of double-dispatching 
operations... at the light of this explaination, you should re-read 
ARM95 13.13, and may better understand them.

so, now you understand this, you may ask yourself if you really need 
to use Receive_Socket() or Send_Socket(): they are intended to 
programmers writing their own stream attributes... (note that this 
could be useful to communicate with a C program through socket streams).

i hope this explaination clarified things a bit and was useful to you 
(or others)... language lawyers will surely push it a little bit further.

-- 
rien



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 12:11 ` Adrien Plisson
@ 2005-05-02 14:55   ` fabio de francesco
  2005-05-02 16:10     ` Adrien Plisson
  2005-05-02 19:39     ` Björn
  0 siblings, 2 replies; 23+ messages in thread
From: fabio de francesco @ 2005-05-02 14:55 UTC (permalink / raw)


Adrien Plisson wrote:
> fabio de francesco wrote:
> > Hello,
>
> hello !
>
> > Today is the first time I try to use sockets in Ada programs, even
if I
> > have some practical knowledge of programming with TCP/IP sockets in
C.
> > Because I didn't find any better tutorial on working with
GNAT.Sockets
> > I am relying on comments in file g-socket.ads from GCC/GNAT sources
> > where there is not a complete and detailed coverage of the subject.
> >
> > (1) Do you know any better tutorial?
>
> personnally, no. the GNAT reference manual says:
> "The chapter here simply gives a brief summary of the facilities
> available. The full documentation is found in the spec file for the
> package. The full sources of these library packages, including both
> spec and body, are provided with all GNAT releases."
> so, you can rely on the comments in g-socket.ads (which contains some

> full examples).

>From my message: "...I am relying on comments in file g-socket.ads from
GCC/GNAT sources...". Sorry for my poor English, I know that sometimes
I'm unable to express clearly, but I had already done exactly what you
now suggest.

> also, the behavior is identical to other sockets
> implementation (C, Python, or others) so don't hesitate to read
> manuals for other languages.

I also said I already know how to program with sockets in C.

> the only big difference is in Streams, which is Ada specific...

This is the only problem I wrote I had. I didn't know how to use
Send_Socket() and Receive_Socket() because the specs say they take
"Stream_Element_Array" and "Stream_Element_Offset" as parameters.

If you read g-socket.ads you won't find any usage example either of the
above mentioned functions or related parameters.

> [...]
> > I hadn't too many problems with exchanging messages and everything
> > works. The problem is that I was only able to use Streams for
> > communicating between them and I can't understand at all how to use
> > Receive_Socket() and Send_Socket() because they use
> > "Stream_Element_Array" and "Stream_Element _Offset" in place of
> > Strings. I know that by using Streams they can't communicate with C
> > programs and I've read that Streams are everything but efficient.
>
> streams are not specially inefficient (to the contrary, my dear). the

> problem is that many people do not clearly understand them !

That was what I have found by searching and reading this NG through
Google for help in using them right before posting.

> so let's explain Ada streams:
>
> streams are defined as a tagged record in Ada.Streams, which is to be

> derived in order to implement stream specific behavior: how to send
or
> receive data from stream. Streams define 2 procedures for reading and

> writing data onto them. on this side of streams, data are represented

> as Stream_Element grouped in Stream_Element_Array. a single
> Stream_Element may represent a byte you send over the network for
> example.
>
> at this end of streams, there is no data type: what is important is
> the type of streams you manipulate.
>
> on the other end, you are concerned with data types you read from or
> write to stream, but not with the type of streams. on this end, every

> streams are equal, may it be file, socket, or anything else. this is
> achieved through stream oriented attributes: 'Read, 'Write, 'Input
and
> 'Output. those attributes allow you to read or write a specific data
> type from/to a stream. for example: Integer'Input( S ) will read an
> integer from the stream S (whatever stream type S is). the behavior
of
> those attribute may be overriden through an attribute definition
clause.
>
> at this end of streams, there is no stream type: what is important is

> the type of data you manipulate.
>
> in fact, stream attributes are kind of double-dispatching
> operations... at the light of this explaination, you should re-read
> ARM95 13.13, and may better understand them.

Thank you for this detailed explanation.

> so, now you understand this, you may ask yourself if you really need
> to use Receive_Socket() or Send_Socket(): they are intended to
> programmers writing their own stream attributes... (note that this
> could be useful to communicate with a C program through socket
streams).

This is exactly the problem that I have overcome with the help I've had
from Eric Jacoboni. Both my client and server programs didn't work at
exchanging messages with C programs. After searching the web I
discovered I had to use Receive_Socket() and Send_Socket() in order to
get over that problem.

S : String := "Hello";
SEA : Stream_Element_Array(1..S'Length);
for SEA'Address use S(S'First)'Address;
Last : Stream_Element_Offset;
Send_Socket( Socket, SEA, Last );

This is not exactly what someone can find in a Python or C manual. :-)

You're right about the fact that the fault is mine for not knowing
Streams while a Socket package isn't required to give any explanations
on the usage of a subject that is not so closely related.

Anyway the package authors cover about 350 lines with an procedure
example only using Streams, without ever saying why and when you should
sometimes choose Receive_Socket() and Send_Socket() in place of
Streams.

> i hope this explaination clarified things a bit and was useful to you

> (or others)... language lawyers will surely push it a little bit
further.
>
> --
> rien

Thanks, it helped a lot to make me to understand Streams. I hope this
time I have been able to make myself clear. 

fabio de francesco




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 14:55   ` fabio de francesco
@ 2005-05-02 16:10     ` Adrien Plisson
  2005-05-02 17:56       ` Eric Jacoboni
  2005-05-02 19:39     ` Björn
  1 sibling, 1 reply; 23+ messages in thread
From: Adrien Plisson @ 2005-05-02 16:10 UTC (permalink / raw)


fabio de francesco wrote:
>>From my message: "...I am relying on comments in file g-socket.ads from
> GCC/GNAT sources...". Sorry for my poor English, I know that sometimes
> I'm unable to express clearly, but I had already done exactly what you
> now suggest.
[...]
> I also said I already know how to program with sockets in C.

i'm sorry if you misunderstood my words: i just wanted to make clear 
that you did exactly what you had to do, and that there was no other 
way to go.

>>the only big difference is in Streams, which is Ada specific...

(this was just an introduction for the next big paragraph...)(french 
style)

[...]
> Thank you for this detailed explanation.

you're welcome !

> This is exactly the problem that I have overcome with the help I've had
> from Eric Jacoboni. Both my client and server programs didn't work at
> exchanging messages with C programs. After searching the web I
> discovered I had to use Receive_Socket() and Send_Socket() in order to
> get over that problem.

that's plain wrong...

the problem is the use of attributes 'Output on arrays which output 
array bounds before array data. and since String is an array, 
String'Output outputs String bounds before string data. (in Ada you 
are no more in C: a string is not delimited by a null character but 
has a lower and an upper bound).

those bounds are always getting in the way when:
1. you are not aware of their existence on the stream
2. the reader of the stream is not an ada program.

anyway, you can get rid of those bounds by using 'Read and 'Write 
instead of 'Input and 'Output. BUT you have to know that using 'Read 
on unconstrained arrays (especially on String) is... well... A Bad 
Thing(tm). (i'm not even sure it works).

you should note that the problem is the same in C: when reading a 
string (sorry an array of char) from a socket, you don't know its 
length. how can you say you read the whole string, and not a sub-part, 
or worst, the whole string plus the beginning of the following data ?

if you can overcome this problem in C, rest assured you can overcome 
it in Ada...
(the exact default behavior for stream attributes is detailed in ARM95 
13.13.2: this includes the behavior for array bounds, type 
discriminants, tags...)

> S : String := "Hello";
> SEA : Stream_Element_Array(1..S'Length);
> for SEA'Address use S(S'First)'Address;
> Last : Stream_Element_Offset;
> Send_Socket( Socket, SEA, Last );

(i'm sorry i'm gonna be a bit rude) beuark !

this is implementation dependant:
- what if Character'Size /= Stream_Element'Size ?
- what if the memory organization of Stream_Element_Array does not 
match the one for a String ?
(i'm not sure overlays are not a recommended practice, but i may be wrong)

you'd better write this:

declare
     Socket : Socket_Type;
     Channel : Stream_Access;
begin
     -- open your socket here, then...
     Channel := Stream( Socket );

     String'Write( Channel, "Hello" );
     -- close your socket here...
end;


> This is not exactly what someone can find in a Python or C manual. :-)

i won't put it in an Ada manual either !!

> You're right about the fact that the fault is mine for not knowing
> Streams while a Socket package isn't required to give any explanations
> on the usage of a subject that is not so closely related.

it is not your fault, it is just that manuals/tutorials don't tell 
much about streams. and don't worry, it took me a long time to 
understand streams. i just don't want people to encounter the same 
problems i had with them, that's why i always try to "demystify" streams.

> Anyway the package authors cover about 350 lines with an procedure
> example only using Streams, without ever saying why and when you should
> sometimes choose Receive_Socket() and Send_Socket() in place of
> Streams.

maybe because you just don't need them ! or only need them when you 
plainly understand what's behind them.

> Thanks, it helped a lot to make me to understand Streams. I hope this
> time I have been able to make myself clear. 

you already made yourself clear...

-- 
rien



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 16:10     ` Adrien Plisson
@ 2005-05-02 17:56       ` Eric Jacoboni
  2005-05-02 18:30         ` Poul-Erik Andreasen
  2005-05-02 20:44         ` Adrien Plisson
  0 siblings, 2 replies; 23+ messages in thread
From: Eric Jacoboni @ 2005-05-02 17:56 UTC (permalink / raw)


In article <42765108$0$22419$ba620e4c@news.skynet.be>, Adrien Plisson
<aplisson-news@stochastique.net> wrote:


> > S : String := "Hello";
> > SEA : Stream_Element_Array(1..S'Length);
> > for SEA'Address use S(S'First)'Address;
> > Last : Stream_Element_Offset;
> > Send_Socket( Socket, SEA, Last );
> 
> (i'm sorry i'm gonna be a bit rude) beuark !

Agree. It's not the sort of things i expected to write with Ada... But,
that's the only code that fits my needs.

> this is implementation dependant:
> - what if Character'Size /= Stream_Element'Size ?
> - what if the memory organization of Stream_Element_Array does not 
> match the one for a String ?

For the second point, Stream_Element_Array is defined as an array of
Stream_Element, so i suppose it match the memory organization of a
String, isn't it ?

> you'd better write this:
> 
> declare
>      Socket : Socket_Type;
>      Channel : Stream_Access;
> begin
>      -- open your socket here, then...
>      Channel := Stream( Socket );
> 
>      String'Write( Channel, "Hello" );
>      -- close your socket here...
> end;

Have you tried this code with a server not Ada aware? Have you tried to
exchange messages with, say, a POP3 server? (to send and to read) I've
tried to use Streams for that, but i never succeeded to make it work...
If a cleaner solution exists, why the hell cannot we find _any_
example?

-- 
jaco



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 17:56       ` Eric Jacoboni
@ 2005-05-02 18:30         ` Poul-Erik Andreasen
  2005-05-02 19:10           ` Simon Wright
  2005-05-02 20:37           ` TCP/IP Sockets with GNAT.Sockets fabio de francesco
  2005-05-02 20:44         ` Adrien Plisson
  1 sibling, 2 replies; 23+ messages in thread
From: Poul-Erik Andreasen @ 2005-05-02 18:30 UTC (permalink / raw)


Eric Jacoboni wrote:
> In article <42765108$0$22419$ba620e4c@news.skynet.be>, Adrien Plisson
> <aplisson-news@stochastique.net> wrote:
> 
> 
> 
>>>S : String := "Hello";
>>>SEA : Stream_Element_Array(1..S'Length);
>>>for SEA'Address use S(S'First)'Address;
>>>Last : Stream_Element_Offset;
>>>Send_Socket( Socket, SEA, Last );
>>
>>(i'm sorry i'm gonna be a bit rude) beuark !
> 
> 
> Agree. It's not the sort of things i expected to write with Ada... But,
> that's the only code that fits my needs.
> 
> 
>>this is implementation dependant:
>>- what if Character'Size /= Stream_Element'Size ?
>>- what if the memory organization of Stream_Element_Array does not 
>>match the one for a String ?
> 
> 
> For the second point, Stream_Element_Array is defined as an array of
> Stream_Element, so i suppose it match the memory organization of a
> String, isn't it ?
> 
> 
>>you'd better write this:
>>
>>declare
>>     Socket : Socket_Type;
>>     Channel : Stream_Access;
>>begin
>>     -- open your socket here, then...
>>     Channel := Stream( Socket );
>>
>>     String'Write( Channel, "Hello" );
>>     -- close your socket here...
>>end;
> 
> 
> Have you tried this code with a server not Ada aware? Have you tried to
> exchange messages with, say, a POP3 server? (to send and to read) I've
> tried to use Streams for that, but i never succeeded to make it work...
> If a cleaner solution exists, why the hell cannot we find _any_
> example?
> 
I have, actually i am using it rigth now and i works. however If the 
other end of the socket is a C-style server it will probely demand 
somthing like the following:

String'Write( Channel, "Hello" & character'first);

when i read i read characters and stop when i reach  character'first.

Here is a fixed string sulution

declare
    Channel := Stream( Socket );
    Word : string(1.. max_word);
    counter : natural := 1	
begin
   loop
      word(counter) := Character'Input (Channel);
      exit when  word(counter) = Character'First;
      counter := counter + 1;
   end loop;
   -- her do what you have to do with Word(1..(counter -1))
end;

BTW my C-couterpart program dosn't seems to have anything against
String'Output( Channel, "Hello" & character'first) ?





^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 18:30         ` Poul-Erik Andreasen
@ 2005-05-02 19:10           ` Simon Wright
  2005-05-03 13:00             ` Poul-Erik Andreasen
  2005-05-02 20:37           ` TCP/IP Sockets with GNAT.Sockets fabio de francesco
  1 sibling, 1 reply; 23+ messages in thread
From: Simon Wright @ 2005-05-02 19:10 UTC (permalink / raw)


Poul-Erik Andreasen <poulerik@pea.dk> writes:

> BTW my C-couterpart program dosn't seems to have anything against
> String'Output( Channel, "Hello" & character'first) ?

Well, that _ought_ to send

(a) 4 bytes == 1, which is the lower index of the string
(b) 4 bytes == 6, which is the upper index of the string
(c) the null-terminated string.

So it depends what your C-counterpart did with those strange
characers.

Why do you say Character'First & not ASCII.NUL?

If you don't want to include the bounds, use 'Write.

There's nothing wrong with streams, but you do have to know exactly
what the language requires the compiler to do!



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 14:55   ` fabio de francesco
  2005-05-02 16:10     ` Adrien Plisson
@ 2005-05-02 19:39     ` Björn
  2005-05-02 20:22       ` fabio de francesco
  1 sibling, 1 reply; 23+ messages in thread
From: Björn @ 2005-05-02 19:39 UTC (permalink / raw)


> If you read g-socket.ads you won't find any usage example either of
the
> above mentioned functions or related parameters.

I agree that the documentation of g-sockets could have been a bit more
verbose.
Having just completed a program that uses a lot of stuff from g-sockets
I learned two things the hard way:
* Using g-socket streams to send records does not guarantee that the
whole record will be sent in one TCP frame.
* UDP/Broadcast does not work well with g-sockets streams.

If you are planning to do any serious work with sockets I would
recommend to go with Send/Receive instead.

Best regards
Björn




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 19:39     ` Björn
@ 2005-05-02 20:22       ` fabio de francesco
  2005-05-09  4:03         ` Dave Thompson
  0 siblings, 1 reply; 23+ messages in thread
From: fabio de francesco @ 2005-05-02 20:22 UTC (permalink / raw)



Björn wrote:
> > If you read g-socket.ads you won't find any usage example either of
> the
> > above mentioned functions or related parameters.
>
> I agree that the documentation of g-sockets could have been a bit
more
> verbose.
> Having just completed a program that uses a lot of stuff from
g-sockets
> I learned two things the hard way:
> * Using g-socket streams to send records does not guarantee that the
> whole record will be sent in one TCP frame.

TCP is a byte-stream protocol with NO record boundaries. When reading
from a TCP socket in a C program we have always to code the read() in a
loop and terminate only when no more characters are read (function
returns value 0 of type "ssize_t" that could be an Integer in Ada I
suppose).

> * UDP/Broadcast does not work well with g-sockets streams.
>
> If you are planning to do any serious work with sockets I would
> recommend to go with Send/Receive instead.

Are Send/Receive Ada functions?

> Best regards
> Björn

Ciao,

fabio de francesco




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 18:30         ` Poul-Erik Andreasen
  2005-05-02 19:10           ` Simon Wright
@ 2005-05-02 20:37           ` fabio de francesco
  2005-05-02 20:52             ` Adrien Plisson
  2005-05-03 13:17             ` Poul-Erik Andreasen
  1 sibling, 2 replies; 23+ messages in thread
From: fabio de francesco @ 2005-05-02 20:37 UTC (permalink / raw)


Poul-Erik Andreasen wrote:
>
> [...]
>
> I have, actually i am using it rigth now and i works. however If the
> other end of the socket is a C-style server it will probely demand
> somthing like the following:

How can you know a priori if a remote service is coded in C or Ada or
everything else?

>
> String'Write( Channel, "Hello" & character'first);
>
> when i read i read characters and stop when i reach  character'first.
>
> Here is a fixed string sulution
>
> declare
>     Channel := Stream( Socket );
>     Word : string(1.. max_word);
>     counter : natural := 1
> begin
>    loop
>       word(counter) := Character'Input (Channel);
>       exit when  word(counter) = Character'First;
>       counter := counter + 1;
>    end loop;
>    -- her do what you have to do with Word(1..(counter -1))
> end;

Is your code reading character by character? If it is I don't think you
can use it for designing efficient programs.

> BTW my C-couterpart program dosn't seems to have anything against
> String'Output( Channel, "Hello" & character'first) ?

What I understand from this thread is that T'Output and T'Input add
some metadata to the stream. If it is true, communicating programs in
other languages must know how to read/write the streams in order to
differentiate data from metadata. May be your C-counterpart program
contains an algorithm that knows how to do it.

Ciao,

fabio de francesco




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 17:56       ` Eric Jacoboni
  2005-05-02 18:30         ` Poul-Erik Andreasen
@ 2005-05-02 20:44         ` Adrien Plisson
  2005-05-02 22:10           ` Eric Jacoboni
  1 sibling, 1 reply; 23+ messages in thread
From: Adrien Plisson @ 2005-05-02 20:44 UTC (permalink / raw)


Eric Jacoboni wrote:
>>(i'm sorry i'm gonna be a bit rude) beuark !
> 
> Agree. It's not the sort of things i expected to write with Ada... But,
> that's the only code that fits my needs.

i would rather say: that's the only way you found to fit your need. 
remember the old Perl adage: there is more than one way to do it !

>>this is implementation dependant:
>>- what if Character'Size /= Stream_Element'Size ?
>>- what if the memory organization of Stream_Element_Array does not 
>>match the one for a String ?
> 
> For the second point, Stream_Element_Array is defined as an array of
> Stream_Element, so i suppose it match the memory organization of a
> String, isn't it ?

Stream_Element_Array matches the organization of an array, BUT:
- Stream_Element is implementation defined (see ARM95 13.13.1), and this 
does not guarantee Stream_Element'Size = Character'Size (unless i missed 
something). strangely, it is 8 bits wide on every platform i used, but i 
would not bet on it for "exotic" 36 bit platforms for example...

- Stream_Element_Array may, for efficiency reason, use a different 
convention than String, which would render them incompatible.
(pragma Convention( C, Stream_Element_Array) for example)

- the original code was:
for SEA'Address use S(S'First)'Address;
which places SEA at the address of the first component of S. this is 
different from:
for SEA'Address use S'Address;
however, i'm not fond of overlay, so don't ask me to explain why it is 
this way...

> Have you tried this code with a server not Ada aware? Have you tried to
> exchange messages with, say, a POP3 server? (to send and to read) I've
> tried to use Streams for that, but i never succeeded to make it work...
> If a cleaner solution exists, why the hell cannot we find _any_
> example?

this is my Ada client:
=========================================================================
with Ada.Text_IO,
      GNAT.Sockets;
procedure Main is
     use GNAT.Sockets;

     Address  : Sock_Addr_Type := (Family_Inet, Inet_Addr( "127.0.0.1" 
), 5555);
     Socket   : Socket_Type;
     Channel  : Stream_Access;

     Data : String := "hello";

begin
     Initialize;
     Create_Socket( Socket );
     Connect_Socket( Socket, Address );
     Channel := Stream( Socket );

     String'Write( Channel, Data );
     String'Read( Channel, Data );
     Ada.Text_IO.Put_Line( Data );

     Close_Socket( Socket );
     Finalize;
end Main;
=========================================================================

this is my Python server:
=========================================================================
import socket

def main():
     server = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
     server.bind( ('127.0.0.1', 5555) )
     server.listen( 5 )

     client, addr = server.accept()

     data = ''
     while len( data ) != 5:
         data += client.recv( 5 )
     print data
     client.send( "world" )

     server.close()

if __name__ == '__main__':
     main()
=========================================================================

they work together like a charm. ok, ok, ok, i admit it i cheated !!
the ada client sends a 5 character long string and waits for a 5 
character long string, but the server sends a 5 character long string... 
if the server sent "grabuuuu !", the client would only get "grabu".

as i already pointed to you on fr.comp.lang.ada, what you get from a 
read is dependant on the PROTOCOL !

all the problem encountered when using streams with sockets are protocol 
problems: people sends some data on the socket and expect something else 
at the other end. in my example, i used a simple protocol: the client 
send 5 characters on the socket then the server sends back 5 other 
characters. the protocol is the same on both sides.

when trying to sends  strings over the network, you have to take into 
account that no 2 languages uses the same representation for strings: C 
strings are null-terminated, Ada strings are arrays of character with a 
lower and an upper bound, pascal strings are array of chars with only an 
upper bound... if you just send c strings and expect ada strings, you 
only get garbage !

this is the point of knowing ARM95 13.13.2: it allows you to know HOW 
data are pushed onto streams, thus allowing you to know how to read them 
back. eventually, you can write your own 'Read and 'Write procedures so 
that you are sure of what you have on the stream... ultimately, you can 
combine all the techniques to define powerful language-independant 
protocols !

-- 
rien




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 20:37           ` TCP/IP Sockets with GNAT.Sockets fabio de francesco
@ 2005-05-02 20:52             ` Adrien Plisson
  2005-05-03 12:04               ` fabio de francesco
  2005-05-03 13:17             ` Poul-Erik Andreasen
  1 sibling, 1 reply; 23+ messages in thread
From: Adrien Plisson @ 2005-05-02 20:52 UTC (permalink / raw)


fabio de francesco wrote:
> How can you know a priori if a remote service is coded in C or Ada or
> everything else?

you don't and you should NEVER assume such a thing. but you should know 
what protocol is to be used between the client and the server. if the 
protocol is well-defined (that is: in a language independant way) there 
is no problem in making any software in any language communicate...

> Is your code reading character by character? If it is I don't think you
> can use it for designing efficient programs.

why not ?

another question for you: do you use TCP connections to send small 
packets ? those TCP frames that can achieve more than 50% overhead are 
really not efficient...

> May be your C-counterpart program
> contains an algorithm that knows how to do it.

or simply ignore those characters which are non-printable, which is the 
case with small strings...

-- 
rien




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 20:44         ` Adrien Plisson
@ 2005-05-02 22:10           ` Eric Jacoboni
  2005-05-02 23:42             ` tmoran
  0 siblings, 1 reply; 23+ messages in thread
From: Eric Jacoboni @ 2005-05-02 22:10 UTC (permalink / raw)


In article <42769099$0$24172$ba620e4c@news.skynet.be>, Adrien Plisson
<aplisson-news@stochastique.net> wrote:

> this is my Ada client:

Thanks, i'm gonna try to adapt it to my needs...

> =========================================================================
> with Ada.Text_IO,
>       GNAT.Sockets;
> procedure Main is
>      use GNAT.Sockets;
> 
>      Address  : Sock_Addr_Type := (Family_Inet, Inet_Addr( "127.0.0.1" 
> ), 5555);
>      Socket   : Socket_Type;
>      Channel  : Stream_Access;
> 
>      Data : String := "hello";
> 
> begin
>      Initialize;
>      Create_Socket( Socket );
>      Connect_Socket( Socket, Address );
>      Channel := Stream( Socket );
> 
>      String'Write( Channel, Data );
>      String'Read( Channel, Data );
>      Ada.Text_IO.Put_Line( Data );
> 
>      Close_Socket( Socket );
>      Finalize;
> end Main;

> as i already pointed to you on fr.comp.lang.ada, what you get from a 
> read is dependant on the PROTOCOL !

Well... Given the POP3 RFC:

"Responses in the POP3 consist of a status indicator and a keyword
   possibly followed by additional information.  All responses are
   terminated by a CRLF pair.  Responses may be up to 512 characters
   long, including the terminating CRLF.  "

So, i understand i have to read in a string and that's how i do with
every language i know. The pb with your exemple is that you have wrote
both the server and the client : you know the server will always send
fixed length strings, but that's not the case in real life. Sometimes
the POP3 server will send a "+OK", sometimes a "+OK 20 40", sometimes
another string. The protocol itself doesnt convey the length of the
answer and that's also true with other well known Internet protocols.
How to manage this with a Ada String ? I admit i don't see how to do.

> ultimately, you can 
> combine all the techniques to define powerful language-independant 
> protocols !

I don't want to define protocols, i just want be able to use an
existing protocol and to speak with a server that follow a well known
RFC.

-- 
jaco



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 22:10           ` Eric Jacoboni
@ 2005-05-02 23:42             ` tmoran
  0 siblings, 0 replies; 23+ messages in thread
From: tmoran @ 2005-05-02 23:42 UTC (permalink / raw)


For POP3 and a bunch of other stuff you need an IO layer that buffers
input and lets you read LF terminated strings, similar to
Ada.Text_IO.Get_Line.  eg

  type Socket_Type(Max_Line_Length: Positive)
  is new NC.Sockets.Socket_Type with private;

  procedure Get_Line(Socket  : in out Socket_Type;
                     Line    :    out String;
                     Last    :    out Natural;
                     Timeout : in     Duration := 30.0);
    -- Return Line(Line'first .. Last)
    -- Input up through LF if LF occurs,
    -- Line(Line'range) if no LF seen,
    -- or Input up through last received char if timeout or hangup



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 20:52             ` Adrien Plisson
@ 2005-05-03 12:04               ` fabio de francesco
  2005-05-03 12:22                 ` Adrien Plisson
  0 siblings, 1 reply; 23+ messages in thread
From: fabio de francesco @ 2005-05-03 12:04 UTC (permalink / raw)


Adrien Plisson wrote:

> fabio de francesco wrote:
> > How can you know a priori if a remote service is coded in C or Ada
or
> > everything else?

> you don't and you should NEVER assume such a thing. but you should
know
> what protocol is to be used between the client and the server. if the

> protocol is well-defined (that is: in a language independant way)
there
> is no problem in making any software in any language communicate...

Ciao,

I know that. I've been programming networking software in C for years.

I only objected to that statement: "... however If the other end of the
socket is a C-style server it will probely demand somthing like the
following:..."

> > Is your code reading character by character? If it is I don't think
you
> > can use it for designing efficient programs.

> why not ?

I supposed that Ada and C aren't different in that. I mean that, when a
C program is to read/write a lot of data from/to a disk file or any
other device, it is preferred to read/write large chunks of bytes
altogether:

    FILE *in, *out;
    size_t nread;
    char buffer[BUFSIZ];

    in = fopen ("file.in", "r");
    out = fopen ("file.out", "w");

    while ((nread = fread(buffer,sizeof(char),sizeof(buffer),in)) > 0)
        fwrite(buffer,sizeof(char),nread,out);

    fclose (in);
    fclose (out);

The first code is faster (20% on my machine) than the following:

 char b;
 while ((nread = fread(&b,sizeof(char),1,in)) > 0)
     fwrite(&b,sizeof(char),1,out);

> another question for you: do you use TCP connections to send small
> packets ? those TCP frames that can achieve more than 50% overhead
are
> really not efficient...

What does make you think that? If you refer to my posted code, it was
only a test to get acquainted to GNAT.Sockets.

> > May be your C-counterpart program
> > contains an algorithm that knows how to do it.
>
> or simply ignore those characters which are non-printable, which is
the
> case with small strings...
> 
> -- 
> rien

Regards,

fabio de francesco




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-03 12:04               ` fabio de francesco
@ 2005-05-03 12:22                 ` Adrien Plisson
  0 siblings, 0 replies; 23+ messages in thread
From: Adrien Plisson @ 2005-05-03 12:22 UTC (permalink / raw)


fabio de francesco wrote:
> I only objected to that statement: "... however If the other end of the
> socket is a C-style server it will probely demand somthing like the
> following:..."

sorry, i misunderstood your statement...

> I supposed that Ada and C aren't different in that. I mean that, when a
> C program is to read/write a lot of data from/to a disk file or any
> other device, it is preferred to read/write large chunks of bytes
> altogether:

you are right, it is faster. but there are some cases where you can't 
read chunks, especially when you don't know the size of the data you 
have to read and you can't read too much data.

> What does make you think that? If you refer to my posted code, it was
> only a test to get acquainted to GNAT.Sockets.

i hope so ! but i've already seen people doing this...

-- 
rien



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 19:10           ` Simon Wright
@ 2005-05-03 13:00             ` Poul-Erik Andreasen
  2005-05-03 21:48               ` Simon Wright
  2005-05-04  8:01               ` Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets) Adrien Plisson
  0 siblings, 2 replies; 23+ messages in thread
From: Poul-Erik Andreasen @ 2005-05-03 13:00 UTC (permalink / raw)


Simon Wright wrote:
> Poul-Erik Andreasen <poulerik@pea.dk> writes:
> 
> 
>>BTW my C-couterpart program dosn't seems to have anything against
>>String'Output( Channel, "Hello" & character'first) ?
> 
> 
> Well, that _ought_ to send
> 
> (a) 4 bytes == 1, which is the lower index of the string
> (b) 4 bytes == 6, which is the upper index of the string
> (c) the null-terminated string.


> So it depends what your C-counterpart did with those strange
> characers.

It probely  just trow them away, i think the reson why is not a problem 
is that besides being zero terminated the the messages that i sent are
requered to start with '$', Anyway i will, ofcourse change to
string'write

> 
> Why do you say Character'First & not ASCII.NUL?

Not for any partikulari reason.

When i started developing job i tried with ASCII.NUL
things didn't work out(surely for som other reason);
they did when i first was using character'first.
(also surely for som other reason);

Are there any reason why ASCII.NUL should be better;

ASCII.NUL are defined as Character'First;

> If you don't want to include the bounds, use 'Write.

I will

> There's nothing wrong with streams, but you do have to know exactly
> what the language requires the compiler to do!

Therefor this is realy a nice thread :-)



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 20:37           ` TCP/IP Sockets with GNAT.Sockets fabio de francesco
  2005-05-02 20:52             ` Adrien Plisson
@ 2005-05-03 13:17             ` Poul-Erik Andreasen
  1 sibling, 0 replies; 23+ messages in thread
From: Poul-Erik Andreasen @ 2005-05-03 13:17 UTC (permalink / raw)


fabio de francesco wrote:
> Poul-Erik Andreasen wrote:
> 
>>[...]
>>
>>I have, actually i am using it rigth now and i works. however If the
>>other end of the socket is a C-style server it will probely demand
>>somthing like the following:
> 
> 
> How can you know a priori if a remote service is coded in C or Ada or
> everything else?

You can't, but i make no differens as long as you have the API.
If the API requires zeroterminated strings it what you could call
a c-style API. It can be written in any langauge, also in Ada and '
still be a C.style

> 
>>String'Write( Channel, "Hello" & character'first);
>>
>>when i read i read characters and stop when i reach  character'first.
>>
>>Here is a fixed string sulution
>>
>>declare
>>    Channel := Stream( Socket );
>>    Word : string(1.. max_word);
>>    counter : natural := 1
>>begin
>>   loop
>>      word(counter) := Character'Input (Channel);
>>      exit when  word(counter) = Character'First;
>>      counter := counter + 1;
>>   end loop;
>>   -- her do what you have to do with Word(1..(counter -1))
>>end;
> 
> 
> Is your code reading character by character? If it is I don't think you
> can use it for designing efficient programs.

At some level the program vill have to deal with bytes individualy 
anyway, you could asume that the build in procedure are better
optimized, but i dont think that the overhead is significant
as long as you use a fixed string as buffer. If you using 
unbounded_strings, and are adding the incomming character it is a quite 
different story;
> 
>>BTW my C-couterpart program dosn't seems to have anything against
>>String'Output( Channel, "Hello" & character'first) ?
> 
> 
> What I understand from this thread is that T'Output and T'Input add
> some metadata to the stream. If it is true, communicating programs in
> other languages must know how to read/write the streams in order to
> differentiate data from metadata. May be your C-counterpart program
> contains an algorithm that knows how to do it.

Yes it requere a special start character.


Greeting

Poul-Erik Andreasen



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-03 13:00             ` Poul-Erik Andreasen
@ 2005-05-03 21:48               ` Simon Wright
  2005-05-04  8:01               ` Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets) Adrien Plisson
  1 sibling, 0 replies; 23+ messages in thread
From: Simon Wright @ 2005-05-03 21:48 UTC (permalink / raw)


Poul-Erik Andreasen <poulerik@pea.dk> writes:

> Simon Wright wrote:

>> Why do you say Character'First & not ASCII.NUL?
>
> Not for any partikulari reason.
>
> When i started developing job i tried with ASCII.NUL
> things didn't work out(surely for som other reason);
> they did when i first was using character'first.
> (also surely for som other reason);
>
> Are there any reason why ASCII.NUL should be better;
>
> ASCII.NUL are defined as Character'First;

It just seems that ASCII.NUL is a more appropriate name for what you
are trying to send .. I suppose Character'Val (0) would also do. It
seems almost accidental that Character'First gives the value you need
.. the others are more explicitly related to the problem.

Just my 2p!



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets)
  2005-05-03 13:00             ` Poul-Erik Andreasen
  2005-05-03 21:48               ` Simon Wright
@ 2005-05-04  8:01               ` Adrien Plisson
  2005-05-04 13:40                 ` Poul-Erik Andreasen
  1 sibling, 1 reply; 23+ messages in thread
From: Adrien Plisson @ 2005-05-04  8:01 UTC (permalink / raw)


Poul-Erik Andreasen wrote:
> When i started developing job i tried with ASCII.NUL
> things didn't work out(surely for som other reason);
> they did when i first was using character'first.
> (also surely for som other reason);
 >
> Are there any reason why ASCII.NUL should be better;

Character'First do not describe the NUL character. i mean, it is the 
NUL character, but you have to know the implementation details of type 
Character to see that it's first element is the NUL character.

ASCII.NUL states explicitly that you are using the NUL character, 
that's why its use should be better.

anyway, the package ASCII is described in ARM95 J.5, that means it is 
part of "Obsolescent Features". as said in the ARM, "Use of these 
features is not recommended in newly written programs.". so it is 
better than Character'First, but there exists a better way to write this.

the better way is the use of Ada.Characters.Latin_1, which defines a 
constant NUL describing the NUL character. unfortunately, the package 
name is long, so you may have to write a use clause or a rename.

with Ada.Text_IO,
     Ada.Characters.Latin_1;
procedure Test is
     -- see comments below
     use Ada.Characters.Latin_1;
     package ASCII renames Ada.Characters.Latin_1;
     package Characters renames Ada.Characters.Latin_1;

begin
     Ada.Text_IO.Put( Ada.Characters.Latin_1.NUL ); -- a bit long

     Ada.Text_IO.Put( NUL ); -- a bit short, NUL what ?
                             -- NUL Character ? not sure...

     Ada.Text_IO.Put( ASCII.NUL ); -- not recommended, there is
                                   -- a risk of confusion

     Ada.Text_IO.Put( Characters.NUL ); -- this seems better !
end Test;

besides all this, when looking at Ada.Characters.Latin_1, we see that 
NUL is defined this way :

NUL : constant Character := Character'Val(0);
	
so if you just need NUL and want to avoid declarations, you may use 
Character'Val(0), which describes the NUL character better than 
Character'First.

-- 
rien



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets)
  2005-05-04  8:01               ` Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets) Adrien Plisson
@ 2005-05-04 13:40                 ` Poul-Erik Andreasen
  0 siblings, 0 replies; 23+ messages in thread
From: Poul-Erik Andreasen @ 2005-05-04 13:40 UTC (permalink / raw)


Adrien Plisson wrote:
> Poul-Erik Andreasen wrote:
> 
>> When i started developing job i tried with ASCII.NUL
>> things didn't work out(surely for som other reason);
>> they did when i first was using character'first.
>> (also surely for som other reason);
> 
>  >
> 
>> Are there any reason why ASCII.NUL should be better;
> 
> 
> Character'First do not describe the NUL character. i mean, it is the NUL 
> character, but you have to know the implementation details of type 
> Character to see that it's first element is the NUL character.
> 
> ASCII.NUL states explicitly that you are using the NUL character, that's 
> why its use should be better.
> 
> anyway, the package ASCII is described in ARM95 J.5, that means it is 
> part of "Obsolescent Features". as said in the ARM, "Use of these 
> features is not recommended in newly written programs.". so it is better 
> than Character'First, but there exists a better way to write this.
> 
> the better way is the use of Ada.Characters.Latin_1, which defines a 
> constant NUL describing the NUL character. unfortunately, the package 
> name is long, so you may have to write a use clause or a rename.
> 
> with Ada.Text_IO,
>     Ada.Characters.Latin_1;
> procedure Test is
>     -- see comments below
>     use Ada.Characters.Latin_1;
>     package ASCII renames Ada.Characters.Latin_1;
>     package Characters renames Ada.Characters.Latin_1;
> 
> begin
>     Ada.Text_IO.Put( Ada.Characters.Latin_1.NUL ); -- a bit long
> 
>     Ada.Text_IO.Put( NUL ); -- a bit short, NUL what ?
>                             -- NUL Character ? not sure...
> 
>     Ada.Text_IO.Put( ASCII.NUL ); -- not recommended, there is
>                                   -- a risk of confusion
> 
>     Ada.Text_IO.Put( Characters.NUL ); -- this seems better !
> end Test;
> 
> besides all this, when looking at Ada.Characters.Latin_1, we see that 
> NUL is defined this way :
> 
> NUL : constant Character := Character'Val(0);
>     
> so if you just need NUL and want to avoid declarations, you may use 
> Character'Val(0), which describes the NUL character better than 
> Character'First.
> 
point taken

thanks

Poul-Erik Andreasen



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: TCP/IP Sockets with GNAT.Sockets
  2005-05-02 20:22       ` fabio de francesco
@ 2005-05-09  4:03         ` Dave Thompson
  0 siblings, 0 replies; 23+ messages in thread
From: Dave Thompson @ 2005-05-09  4:03 UTC (permalink / raw)


On 2 May 2005 13:22:41 -0700, "fabio de francesco" <fmdf@tiscali.it>
wrote:
<snip>
> TCP is a byte-stream protocol with NO record boundaries. When reading
> from a TCP socket in a C program we have always to code the read() in a
> loop and terminate only when no more characters are read (function

True -- and important: in the typical program-development environment
programs are run in isolation, often slow-stepped, on unloaded
machines in a secluded subnet, and most if not all TCP/IP stacks in
such environments _do_ "accidentally" preserve buffer boundaries, so
that programs depending on this "appear" to work, and only when they
are deployed to the real-world net of long, heterogenous, overloaded,
and varying paths do they fail, and even then "only" occasionally and
unpredictably, except that by Murphy's law some occasions will be when
your most important user(s)/customer(s)/prospect(s)/boss(es) are doing
something particularly important.

Er, -11L I<rant>$ 9L :L I</>$$
(Or, can I combine those as 9:L ? I can't recall.)

> returns value 0 of type "ssize_t" that could be an Integer in Ada I
> suppose).
> 
Socket-for-TCP read() or recv() returns 0 only when the peer has
closed or half-closed, i.e., at "end of file". To read less than all
of the data on the connection (but more than 1 octet) you must code to
read repeatedly (usually in a loop) until you get all of the expected
data, usually determined by a known (fixed or prefix) count or a
delimiter; or with no expectation until a nonblocking socket returns
-1 and sets (the value accessed by) errno to EAGAIN or EWOULDBLOCK or
select/poll indicates no data ready for a sufficient time (which most
simply can be any time at all).

ssize_t will certainly be some integer type. On most machines
addresses are the same "word" size as default integers and thus likely
Integer; and even if the usable object size is much smaller than the
address size and hence nominal address space it is usually convenient
to still use the address size for size_t and ssize_t; but neither of
these is required or guaranteed. Whatever binding(s) you use should
certainly provide a suitable type definition of this for you.

- David.Thompson1 at worldnet.att.net



^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2005-05-09  4:03 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-05-02  2:42 TCP/IP Sockets with GNAT.Sockets fabio de francesco
2005-05-02  5:58 ` Eric Jacoboni
2005-05-02 12:11 ` Adrien Plisson
2005-05-02 14:55   ` fabio de francesco
2005-05-02 16:10     ` Adrien Plisson
2005-05-02 17:56       ` Eric Jacoboni
2005-05-02 18:30         ` Poul-Erik Andreasen
2005-05-02 19:10           ` Simon Wright
2005-05-03 13:00             ` Poul-Erik Andreasen
2005-05-03 21:48               ` Simon Wright
2005-05-04  8:01               ` Character'First, ASCII.NUL and others (Was: Re: TCP/IP Sockets with GNAT.Sockets) Adrien Plisson
2005-05-04 13:40                 ` Poul-Erik Andreasen
2005-05-02 20:37           ` TCP/IP Sockets with GNAT.Sockets fabio de francesco
2005-05-02 20:52             ` Adrien Plisson
2005-05-03 12:04               ` fabio de francesco
2005-05-03 12:22                 ` Adrien Plisson
2005-05-03 13:17             ` Poul-Erik Andreasen
2005-05-02 20:44         ` Adrien Plisson
2005-05-02 22:10           ` Eric Jacoboni
2005-05-02 23:42             ` tmoran
2005-05-02 19:39     ` Björn
2005-05-02 20:22       ` fabio de francesco
2005-05-09  4:03         ` Dave Thompson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox