comp.lang.ada
 help / color / mirror / Atom feed
* GNAT.Sockets. Blocking?
@ 2009-06-23 21:06 Jacob M. H. Smith
  2009-06-24  0:14 ` John B. Matthews
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Jacob M. H. Smith @ 2009-06-23 21:06 UTC (permalink / raw)


Hi,

I'm kind of new to socket programming and I need some help here. I
wrote a simple little program that just fetches Google's index page.
The posted code works, but only because I used a "Connection: close"
header in the HTTP request. How would set up my code responsible for
reading the data from the stream so that I can read the page while
keeping the connection open? If I remove the header the program seems
to stop when calling the Ada.Streams.Read function if there is less
than BUFFER_SIZE data in the streams buffer. Can't I just read as much
as is available?

Thanks in advance.

Here's the code:

-------------------

with Ada.Text_IO;
with Ada.Streams;
with GNAT.Sockets;

procedure Socket_Test is

  procedure Connect (
      Socket  : out GNAT.Sockets.Socket_Type;
      Channel : out GNAT.Sockets.Stream_Access;
      Host    : in  String;
      Port    : in  GNAT.Sockets.Port_Type) is
    HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
        GNAT.Sockets.Get_Host_By_Name (Host);
    Address : GNAT.Sockets.Sock_Addr_Type;
  begin
    --  Prepare the address structure. TODO: make a loop
    Address.Addr := GNAT.Sockets.Addresses (HOST_ENTRY, 1);
    Address.Port := Port;
    --  Set up the connection.
    GNAT.Sockets.Create_Socket (Socket);
    GNAT.Sockets.Connect_Socket (Socket, Address);
    Channel := GNAT.Sockets.Stream (Socket);
    --  TODO: error handling.
  end Connect;

  use type Ada.Streams.Stream_Element_Count;

  BUFFER_SIZE : constant Ada.Streams.Stream_Element_Count := 256;
  HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80;
  CRLF        : constant String := (ASCII.CR, ASCII.LF);
  HOST        : constant String := "www.google.com";

  Socket     : GNAT.Sockets.Socket_Type;
  Channel    : GNAT.Sockets.Stream_Access;
  Byte_Count : Ada.Streams.Stream_Element_Count;
  Buffer     : Ada.Streams.Stream_Element_Array (1 .. BUFFER_SIZE);

begin

  --  Initialize.
  GNAT.Sockets.Initialize;

  --  Connect.
  Connect (Socket, Channel, "www.google.com", HTTP_PORT);

  --  Send HTTP request.
  String'Write (Channel,
      "GET / HTTP/1.1" & CRLF &
      "Host: " & HOST & CRLF &
      "Connection: close" & CRLF &
      CRLF);

  --  Read incoming data.
  loop
    Ada.Streams.Read (Channel.all, Buffer, Byte_Count);
    exit when Byte_Count = 0;
    for I in 1 .. Byte_Count loop
      Ada.Text_IO.Put (Character'Val (Buffer (I)));
    end loop;
  end loop;

end Socket_Test;



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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
@ 2009-06-24  0:14 ` John B. Matthews
  2009-06-24  4:55   ` Jacob M. H. Smith
  2009-06-24  7:47 ` Dmitry A. Kazakov
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: John B. Matthews @ 2009-06-24  0:14 UTC (permalink / raw)


In article 
<158756da-21b7-4e2d-b288-7ba030f1f35c@25g2000yqb.googlegroups.com>,
 "Jacob M. H. Smith" <jacob.m.h.smith@googlemail.com> wrote:

> I'm kind of new to socket programming and I need some help here. I 
> wrote a simple little program that just fetches Google's index page. 
> The posted code works, but only because I used a "Connection: close" 
> header in the HTTP request. How would set up my code responsible for 
> reading the data from the stream so that I can read the page while 
> keeping the connection open? If I remove the header the program seems 
> to stop when calling the Ada.Streams.Read function if there is less 
> than BUFFER_SIZE data in the streams buffer. Can't I just read as 
> much as is available?
[...]

The Google page specifies "Transfer-Encoding: chunked", which must be 
"terminated by closing the connection." To get the whole page, I think  
you'd need to handle the chunk-size:

<http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6>

Your code gets www.example.com correctly, without an explicit 
"Connection: close":

<http://www.rfc-editor.org/rfc/rfc2606.txt>

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: GNAT.Sockets. Blocking?
  2009-06-24  0:14 ` John B. Matthews
@ 2009-06-24  4:55   ` Jacob M. H. Smith
  2009-06-24 14:36     ` John B. Matthews
  0 siblings, 1 reply; 13+ messages in thread
From: Jacob M. H. Smith @ 2009-06-24  4:55 UTC (permalink / raw)


On Jun 24, 2:14 am, "John B. Matthews" <nos...@nospam.invalid> wrote:
> The Google page specifies "Transfer-Encoding: chunked", which must be
> "terminated by closing the connection." To get the whole page, I think  
> you'd need to handle the chunk-size:
>
> <http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6>

Thanks for your reply, but I don't think that's correct. It says
"the set of transfer-codings MUST include "chunked", unless the
message is terminated by closing the connection.". That sounds
to me like there is really no problem in having a persistent
connection and chunked transfer encoding.

> Your code gets www.example.com correctly, without an explicit
> "Connection: close":
>
> <http://www.rfc-editor.org/rfc/rfc2606.txt>

I think that's because example.com closes the connection, no matter
if you request a persistent connection or not. At least on my end
here.



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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
  2009-06-24  0:14 ` John B. Matthews
@ 2009-06-24  7:47 ` Dmitry A. Kazakov
  2009-06-24 13:32 ` anon
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Dmitry A. Kazakov @ 2009-06-24  7:47 UTC (permalink / raw)


On Tue, 23 Jun 2009 14:06:35 -0700 (PDT), Jacob M. H. Smith wrote:

> Can't I just read as much as is available?

Yes, you can, by reading one octet (byte) at a time. Since you don't know
the logical packet size in advance, any incoming octet may indicate the
packet end (when it contains LF, in the case of HTTP).

Search for a earlier discussion in comp.lang.ada concerning reading "lines"
from socket stream (or any other stream, if that matters).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
  2009-06-24  0:14 ` John B. Matthews
  2009-06-24  7:47 ` Dmitry A. Kazakov
@ 2009-06-24 13:32 ` anon
  2009-06-24 14:03 ` anon
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: anon @ 2009-06-24 13:32 UTC (permalink / raw)


I have a couple of programs that preform this type of task.

First, web pages begin with "<html>" and normally end with "</html>". 
Second, each server can be set to use a block size for the page that may be 
256B, 1KB or 4KB. But in some rare cases the server can use odd sizes. Use 
the unsecure "Telnel <server web page>:80" to see what info you will need to 
process. 

Also, some servers (Like the Microsoft Servers) to prevent robot or programs 
like this, request some browsers information or they close the connection. 
And some servers or web pages like 'google" use cookies. And for some server 
that have Ads, if these are not downloaded and a cookie set can block the 
complete page from be transmitted.

And if you play with 'PingPong" a program commented in GNAT.Sockets 
specification file (g-socket.ads) you will se that if you alter the string 
size it will cause the prograsm to block.


A basic outline for this type of program is:

    <<Routine>> Get_String -- Reads a set characters and build a string
                           -- from socket

    <<Routine>> Get_Web_Page -- Read a Web page from the net
    ...
    Line := 1 ;
    Open connection 
    loop 
      Input := Get_String
    until Input = "<html>" loop  -- Should be first string

    Page ( Line ) := Input
    Line := Line + 1 ;

    while Input /= "</html>" loop  -- Should be last string
      Input := Get_String
      Page ( Line ) := Input 
      Line := Line + 1 ;
    end loop 

    Close connection 
    ...
    return Page  -- At this point Page is array of variable lengths 
                 -- strings that contains => "<html>" ... "</html>"

    exception
       when Socket_Error => -- Server close connection 
          -- Process corrupted page???

       when Timeout =>  -- May be needed if Server stop transmitting
          close connection
          -- Process corrupted page???


In <158756da-21b7-4e2d-b288-7ba030f1f35c@25g2000yqb.googlegroups.com>, "Jacob M. H. Smith" <jacob.m.h.smith@googlemail.com> writes:
>Hi,
>
>I'm kind of new to socket programming and I need some help here. I
>wrote a simple little program that just fetches Google's index page.
>The posted code works, but only because I used a "Connection: close"
>header in the HTTP request. How would set up my code responsible for
>reading the data from the stream so that I can read the page while
>keeping the connection open? If I remove the header the program seems
>to stop when calling the Ada.Streams.Read function if there is less
>than BUFFER_SIZE data in the streams buffer. Can't I just read as much
>as is available?
>
>Thanks in advance.
>
>Here's the code:
>
>-------------------
>
>with Ada.Text_IO;
>with Ada.Streams;
>with GNAT.Sockets;
>
>procedure Socket_Test is
>
>  procedure Connect (
>      Socket  : out GNAT.Sockets.Socket_Type;
>      Channel : out GNAT.Sockets.Stream_Access;
>      Host    : in  String;
>      Port    : in  GNAT.Sockets.Port_Type) is
>    HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
>        GNAT.Sockets.Get_Host_By_Name (Host);
>    Address : GNAT.Sockets.Sock_Addr_Type;
>  begin
>    --  Prepare the address structure. TODO: make a loop
>    Address.Addr := GNAT.Sockets.Addresses (HOST_ENTRY, 1);
>    Address.Port := Port;
>    --  Set up the connection.
>    GNAT.Sockets.Create_Socket (Socket);
>    GNAT.Sockets.Connect_Socket (Socket, Address);
>    Channel := GNAT.Sockets.Stream (Socket);
>    --  TODO: error handling.
>  end Connect;
>
>  use type Ada.Streams.Stream_Element_Count;
>
>  BUFFER_SIZE : constant Ada.Streams.Stream_Element_Count := 256;
>  HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80;
>  CRLF        : constant String := (ASCII.CR, ASCII.LF);
>  HOST        : constant String := "www.google.com";
>
>  Socket     : GNAT.Sockets.Socket_Type;
>  Channel    : GNAT.Sockets.Stream_Access;
>  Byte_Count : Ada.Streams.Stream_Element_Count;
>  Buffer     : Ada.Streams.Stream_Element_Array (1 .. BUFFER_SIZE);
>
>begin
>
>  --  Initialize.
>  GNAT.Sockets.Initialize;
>
>  --  Connect.
>  Connect (Socket, Channel, "www.google.com", HTTP_PORT);
>
>  --  Send HTTP request.
>  String'Write (Channel,
>      "GET / HTTP/1.1" & CRLF &
>      "Host: " & HOST & CRLF &
>      "Connection: close" & CRLF &
>      CRLF);
>
>  --  Read incoming data.
>  loop
>    Ada.Streams.Read (Channel.all, Buffer, Byte_Count);
>    exit when Byte_Count = 0;
>    for I in 1 .. Byte_Count loop
>      Ada.Text_IO.Put (Character'Val (Buffer (I)));
>    end loop;
>  end loop;
>
>end Socket_Test;




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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
                   ` (2 preceding siblings ...)
  2009-06-24 13:32 ` anon
@ 2009-06-24 14:03 ` anon
  2009-06-24 15:14 ` Pascal Obry
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: anon @ 2009-06-24 14:03 UTC (permalink / raw)


Also, each Web Page must be open downloaded and then close. and reopen, 
upload requested information wait download result then close. That is, if you 
want to read 10 pages you must open read and close the page 10 times. Its 
just the protocol that is used to access the internet based on a number of RFC. 

To really learn how to access this you should install a server like Apache and 
GNAT's AWS and build a simple set set of web pages.  Write and test your 
program on that server instead of causing problems with an active online 
server.

In <158756da-21b7-4e2d-b288-7ba030f1f35c@25g2000yqb.googlegroups.com>, "Jacob M. H. Smith" <jacob.m.h.smith@googlemail.com> writes:
>Hi,
>
>I'm kind of new to socket programming and I need some help here. I
>wrote a simple little program that just fetches Google's index page.
>The posted code works, but only because I used a "Connection: close"
>header in the HTTP request. How would set up my code responsible for
>reading the data from the stream so that I can read the page while
>keeping the connection open? If I remove the header the program seems
>to stop when calling the Ada.Streams.Read function if there is less
>than BUFFER_SIZE data in the streams buffer. Can't I just read as much
>as is available?
>
>Thanks in advance.
>
>Here's the code:
>
>-------------------
>
>with Ada.Text_IO;
>with Ada.Streams;
>with GNAT.Sockets;
>
>procedure Socket_Test is
>
>  procedure Connect (
>      Socket  : out GNAT.Sockets.Socket_Type;
>      Channel : out GNAT.Sockets.Stream_Access;
>      Host    : in  String;
>      Port    : in  GNAT.Sockets.Port_Type) is
>    HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
>        GNAT.Sockets.Get_Host_By_Name (Host);
>    Address : GNAT.Sockets.Sock_Addr_Type;
>  begin
>    --  Prepare the address structure. TODO: make a loop
>    Address.Addr := GNAT.Sockets.Addresses (HOST_ENTRY, 1);
>    Address.Port := Port;
>    --  Set up the connection.
>    GNAT.Sockets.Create_Socket (Socket);
>    GNAT.Sockets.Connect_Socket (Socket, Address);
>    Channel := GNAT.Sockets.Stream (Socket);
>    --  TODO: error handling.
>  end Connect;
>
>  use type Ada.Streams.Stream_Element_Count;
>
>  BUFFER_SIZE : constant Ada.Streams.Stream_Element_Count := 256;
>  HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80;
>  CRLF        : constant String := (ASCII.CR, ASCII.LF);
>  HOST        : constant String := "www.google.com";
>
>  Socket     : GNAT.Sockets.Socket_Type;
>  Channel    : GNAT.Sockets.Stream_Access;
>  Byte_Count : Ada.Streams.Stream_Element_Count;
>  Buffer     : Ada.Streams.Stream_Element_Array (1 .. BUFFER_SIZE);
>
>begin
>
>  --  Initialize.
>  GNAT.Sockets.Initialize;
>
>  --  Connect.
>  Connect (Socket, Channel, "www.google.com", HTTP_PORT);
>
>  --  Send HTTP request.
>  String'Write (Channel,
>      "GET / HTTP/1.1" & CRLF &
>      "Host: " & HOST & CRLF &
>      "Connection: close" & CRLF &
>      CRLF);
>
>  --  Read incoming data.
>  loop
>    Ada.Streams.Read (Channel.all, Buffer, Byte_Count);
>    exit when Byte_Count = 0;
>    for I in 1 .. Byte_Count loop
>      Ada.Text_IO.Put (Character'Val (Buffer (I)));
>    end loop;
>  end loop;
>
>end Socket_Test;




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

* Re: GNAT.Sockets. Blocking?
  2009-06-24  4:55   ` Jacob M. H. Smith
@ 2009-06-24 14:36     ` John B. Matthews
  0 siblings, 0 replies; 13+ messages in thread
From: John B. Matthews @ 2009-06-24 14:36 UTC (permalink / raw)


In article 
<392f68f1-4eb3-473d-ab9a-d3d8ff524ff3@c9g2000yqm.googlegroups.com>,
 "Jacob M. H. Smith" <jacob.m.h.smith@googlemail.com> wrote:

> On Jun 24, 2:14 am, "John B. Matthews" <nos...@nospam.invalid> wrote:
> > The Google page specifies "Transfer-Encoding: chunked", which must be
> > "terminated by closing the connection." To get the whole page, I think  
> > you'd need to handle the chunk-size:
> >
> > <http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6>
> 
> Thanks for your reply, but I don't think that's correct. It says
> "the set of transfer-codings MUST include "chunked", unless the
> message is terminated by closing the connection.". That sounds
> to me like there is really no problem in having a persistent
> connection and chunked transfer encoding.

Right, but you still have to read the headers, one CRLF-delimited line 
at a time. Then you can read the chunk-size line and chunk-data in a 
loop until the chunk-size is zero. I don't know any way to read lines 
except one octet at a time, as Dmitry suggests:

<http://groups.google.com/group/comp.lang.ada/browse_frm/thread/865c3d125
a8dbc3b/b8dadc91561178d9>

> > Your code gets www.example.com correctly, without an explicit
> > "Connection: close":
> >
> > <http://www.rfc-editor.org/rfc/rfc2606.txt>
> 
> I think that's because example.com closes the connection, no matter
> if you request a persistent connection or not. At least on my end
> here.

I see what you mean; example.com sends the "Connection: close" header, 
which signifies no persistent connection to the client:
...
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8
...
netstat -a | grep http
tcp4  0  0  10.20.30.40.53386  www.example.com.http  LAST_ACK

Otherwise, persistent connections appear to be the default in HTTP 1.1:

<http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html>

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
                   ` (3 preceding siblings ...)
  2009-06-24 14:03 ` anon
@ 2009-06-24 15:14 ` Pascal Obry
  2009-06-24 18:44 ` Simple solution was " anon
  2009-06-24 18:47 ` Per Sandberg
  6 siblings, 0 replies; 13+ messages in thread
From: Pascal Obry @ 2009-06-24 15:14 UTC (permalink / raw)
  To: Jacob M. H. Smith

Jacob,

Not so simple. It all depends on the headers sent back for the web page
your are requesting. If you have a size you need to read the exact
number of bytes. If you have not the size and you have a chunked
transfer encoding you need to read each chunk (see RFC for format) and
catenate the result.

So to keep the connection open you of course do not want to send the
"Connection: close" header. But in this case you must obey the server
headers values.

A good way to learn all this is to read the RFC and the AWS code which
handles all those cases.

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|    http://www.obry.net  -  http://v2p.fr.eu.org
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B



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

* Simple solution was Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
                   ` (4 preceding siblings ...)
  2009-06-24 15:14 ` Pascal Obry
@ 2009-06-24 18:44 ` anon
  2009-06-24 18:47 ` Per Sandberg
  6 siblings, 0 replies; 13+ messages in thread
From: anon @ 2009-06-24 18:44 UTC (permalink / raw)


Here a simple correction of your program that can be use to download any 
web site ( 1..8KB ) from any web server that does not request the browser 
information befoere sending data. Then it dumps the web page to the 
Standard_Output.

Please note: the change in the Http request packet.

  String'Write ( Channel, "GET /"                             & CRLF &
                          "Host: " & HOST                     & CRLF &
                          "Content-Type"                      & CRLF & 
                           CRLF ) ;

Also, I limited the initial web page to 1 .. 8192. Easy adaptable to 
increase buffer size before searching buffer for commands or data 
references. That is needed to resend the next request. 

--
-- Socket_Test
--
with Ada.Text_IO;
with GNAT.Sockets;

procedure Socket_Test is

  procedure Connect ( Socket  : out GNAT.Sockets.Socket_Type ;
                      Channel : out GNAT.Sockets.Stream_Access ;
                      Host    : in  String ;
                      Port    : in  GNAT.Sockets.Port_Type ) is

    HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
                            GNAT.Sockets.Get_Host_By_Name ( Host ) ;
    Address : GNAT.Sockets.Sock_Addr_Type ;

  begin
    --  Prepare the address structure. TODO: make a loop
    Address.Addr :=  GNAT.Sockets.Addresses ( HOST_ENTRY, 1 ) ;
    Address.Port := Port ;

    --  Set up the connection.

    GNAT.Sockets.Create_Socket ( Socket ) ;
    GNAT.Sockets.Connect_Socket ( Socket, Address ) ;
    Channel := GNAT.Sockets.Stream ( Socket ) ;
    --  TODO: error handling.

  exception
    when GNAT.Sockets.Socket_Error => 
      Ada.Text_IO.Put_line ( "Error in connecting to Server" ) ;
  end Connect ;

  HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80 ;
  CRLF        : constant String := ( ASCII.CR, ASCII.LF ) ;
  HOST        : constant String := "www.google.com" ;

  Socket     : GNAT.Sockets.Socket_Type ;
  Channel    : GNAT.Sockets.Stream_Access ;


   Buffer     : String ( 1..8196 ) ;
   Byte_Count : Natural ;

begin

  --  Initialize. No longer used in GNAT 2009
  -- Not really needed in others versions either
--  GNAT.Sockets.Initialize ;

  --  Connect.
  Connect ( Socket, Channel, "www.google.com", HTTP_PORT ) ;

  --  Send HTTP request.
  String'Write ( Channel, "GET /"                             & CRLF &
                          "Host: " & HOST                     & CRLF &
                          "Content-Type"                      & CRLF & 
                           CRLF ) ;

  -- Get Web page
  begin
    Byte_Count := 0 ;
    for Index in Buffer'Range loop
      Byte_Count := Byte_Count + 1 ;
      Character'Read ( Channel, Buffer ( Byte_Count ) ) ;
    end loop ;
  exception
    -- Normal exit if page is less than 8K
    when END_Error =>
       Byte_Count := Byte_Count - 1 ;
  end ;

  if Byte_Count > 0 then
    Ada.Text_IO.Put_Line ( Buffer ( 1 .. Byte_Count ) ) ;
  end if ;

  GNAT.Sockets.Close_Socket ( Socket ) ;

end Socket_Test ;


In <158756da-21b7-4e2d-b288-7ba030f1f35c@25g2000yqb.googlegroups.com>, "Jacob M. H. Smith" <jacob.m.h.smith@googlemail.com> writes:
>Hi,
>
>I'm kind of new to socket programming and I need some help here. I
>wrote a simple little program that just fetches Google's index page.
>The posted code works, but only because I used a "Connection: close"
>header in the HTTP request. How would set up my code responsible for
>reading the data from the stream so that I can read the page while
>keeping the connection open? If I remove the header the program seems
>to stop when calling the Ada.Streams.Read function if there is less
>than BUFFER_SIZE data in the streams buffer. Can't I just read as much
>as is available?
>
>Thanks in advance.
>
>Here's the code:
>
>-------------------
>
>with Ada.Text_IO;
>with Ada.Streams;
>with GNAT.Sockets;
>
>procedure Socket_Test is
>
>  procedure Connect (
>      Socket  : out GNAT.Sockets.Socket_Type;
>      Channel : out GNAT.Sockets.Stream_Access;
>      Host    : in  String;
>      Port    : in  GNAT.Sockets.Port_Type) is
>    HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
>        GNAT.Sockets.Get_Host_By_Name (Host);
>    Address : GNAT.Sockets.Sock_Addr_Type;
>  begin
>    --  Prepare the address structure. TODO: make a loop
>    Address.Addr := GNAT.Sockets.Addresses (HOST_ENTRY, 1);
>    Address.Port := Port;
>    --  Set up the connection.
>    GNAT.Sockets.Create_Socket (Socket);
>    GNAT.Sockets.Connect_Socket (Socket, Address);
>    Channel := GNAT.Sockets.Stream (Socket);
>    --  TODO: error handling.
>  end Connect;
>
>  use type Ada.Streams.Stream_Element_Count;
>
>  BUFFER_SIZE : constant Ada.Streams.Stream_Element_Count := 256;
>  HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80;
>  CRLF        : constant String := (ASCII.CR, ASCII.LF);
>  HOST        : constant String := "www.google.com";
>
>  Socket     : GNAT.Sockets.Socket_Type;
>  Channel    : GNAT.Sockets.Stream_Access;
>  Byte_Count : Ada.Streams.Stream_Element_Count;
>  Buffer     : Ada.Streams.Stream_Element_Array (1 .. BUFFER_SIZE);
>
>begin
>
>  --  Initialize.
>  GNAT.Sockets.Initialize;
>
>  --  Connect.
>  Connect (Socket, Channel, "www.google.com", HTTP_PORT);
>
>  --  Send HTTP request.
>  String'Write (Channel,
>      "GET / HTTP/1.1" & CRLF &
>      "Host: " & HOST & CRLF &
>      "Connection: close" & CRLF &
>      CRLF);
>
>  --  Read incoming data.
>  loop
>    Ada.Streams.Read (Channel.all, Buffer, Byte_Count);
>    exit when Byte_Count = 0;
>    for I in 1 .. Byte_Count loop
>      Ada.Text_IO.Put (Character'Val (Buffer (I)));
>    end loop;
>  end loop;
>
>end Socket_Test;




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

* Re: GNAT.Sockets. Blocking?
  2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
                   ` (5 preceding siblings ...)
  2009-06-24 18:44 ` Simple solution was " anon
@ 2009-06-24 18:47 ` Per Sandberg
  2009-06-24 19:51   ` Pascal Obry
  2009-06-24 22:12   ` Jeffrey R. Carter
  6 siblings, 2 replies; 13+ messages in thread
From: Per Sandberg @ 2009-06-24 18:47 UTC (permalink / raw)


Why not just be lazy??
The folowing 10 lines will achive the same as your 64.

-----------------------------
with Ada.Text_IO;
with AWS.Client;
with AWS.Response;
procedure ThttpGet is
begin
    Ada.Text_IO.Put_Line
      (AWS.Response.Message_Body
         (AWS.Client.Get (URL => "http://www.google.com"))); 

end ThttpGet
-------------------------------
/Per

Jacob M. H. Smith wrote:
> Hi,
> 
> I'm kind of new to socket programming and I need some help here. I
> wrote a simple little program that just fetches Google's index page.
> The posted code works, but only because I used a "Connection: close"
> header in the HTTP request. How would set up my code responsible for
> reading the data from the stream so that I can read the page while
> keeping the connection open? If I remove the header the program seems
> to stop when calling the Ada.Streams.Read function if there is less
> than BUFFER_SIZE data in the streams buffer. Can't I just read as much
> as is available?
> 
> Thanks in advance.
> 
> Here's the code:
> 
> -------------------
> 
> with Ada.Text_IO;
> with Ada.Streams;
> with GNAT.Sockets;
> 
> procedure Socket_Test is
> 
>   procedure Connect (
>       Socket  : out GNAT.Sockets.Socket_Type;
>       Channel : out GNAT.Sockets.Stream_Access;
>       Host    : in  String;
>       Port    : in  GNAT.Sockets.Port_Type) is
>     HOST_ENTRY : constant GNAT.Sockets.Host_Entry_Type :=
>         GNAT.Sockets.Get_Host_By_Name (Host);
>     Address : GNAT.Sockets.Sock_Addr_Type;
>   begin
>     --  Prepare the address structure. TODO: make a loop
>     Address.Addr := GNAT.Sockets.Addresses (HOST_ENTRY, 1);
>     Address.Port := Port;
>     --  Set up the connection.
>     GNAT.Sockets.Create_Socket (Socket);
>     GNAT.Sockets.Connect_Socket (Socket, Address);
>     Channel := GNAT.Sockets.Stream (Socket);
>     --  TODO: error handling.
>   end Connect;
> 
>   use type Ada.Streams.Stream_Element_Count;
> 
>   BUFFER_SIZE : constant Ada.Streams.Stream_Element_Count := 256;
>   HTTP_PORT   : constant GNAT.Sockets.Port_Type := 80;
>   CRLF        : constant String := (ASCII.CR, ASCII.LF);
>   HOST        : constant String := "www.google.com";
> 
>   Socket     : GNAT.Sockets.Socket_Type;
>   Channel    : GNAT.Sockets.Stream_Access;
>   Byte_Count : Ada.Streams.Stream_Element_Count;
>   Buffer     : Ada.Streams.Stream_Element_Array (1 .. BUFFER_SIZE);
> 
> begin
> 
>   --  Initialize.
>   GNAT.Sockets.Initialize;
> 
>   --  Connect.
>   Connect (Socket, Channel, "www.google.com", HTTP_PORT);
> 
>   --  Send HTTP request.
>   String'Write (Channel,
>       "GET / HTTP/1.1" & CRLF &
>       "Host: " & HOST & CRLF &
>       "Connection: close" & CRLF &
>       CRLF);
> 
>   --  Read incoming data.
>   loop
>     Ada.Streams.Read (Channel.all, Buffer, Byte_Count);
>     exit when Byte_Count = 0;
>     for I in 1 .. Byte_Count loop
>       Ada.Text_IO.Put (Character'Val (Buffer (I)));
>     end loop;
>   end loop;
> 
> end Socket_Test;



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

* Re: GNAT.Sockets. Blocking?
  2009-06-24 18:47 ` Per Sandberg
@ 2009-06-24 19:51   ` Pascal Obry
  2009-06-24 22:12   ` Jeffrey R. Carter
  1 sibling, 0 replies; 13+ messages in thread
From: Pascal Obry @ 2009-06-24 19:51 UTC (permalink / raw)
  To: Per Sandberg

Per Sandberg a �crit :
> Why not just be lazy??
> The folowing 10 lines will achive the same as your 64.

And will handle all tricky cases not covered by the program posted :)

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|    http://www.obry.net  -  http://v2p.fr.eu.org
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B



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

* Re: GNAT.Sockets. Blocking?
  2009-06-24 18:47 ` Per Sandberg
  2009-06-24 19:51   ` Pascal Obry
@ 2009-06-24 22:12   ` Jeffrey R. Carter
  2009-06-25 17:30     ` Jacob M. H. Smith
  1 sibling, 1 reply; 13+ messages in thread
From: Jeffrey R. Carter @ 2009-06-24 22:12 UTC (permalink / raw)


Per Sandberg wrote:
> Why not just be lazy??
> The folowing 10 lines will achive the same as your 64.
> 
> -----------------------------
> with Ada.Text_IO;
> with AWS.Client;
> with AWS.Response;
> procedure ThttpGet is
> begin
>    Ada.Text_IO.Put_Line
>      (AWS.Response.Message_Body
>         (AWS.Client.Get (URL => "http://www.google.com")));
> end ThttpGet
> -------------------------------

Looks like 9 lines to me. 5 statements (terminator semicolons).

You need a ';' at the end.

-- 
Jeff Carter
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail
07



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

* Re: GNAT.Sockets. Blocking?
  2009-06-24 22:12   ` Jeffrey R. Carter
@ 2009-06-25 17:30     ` Jacob M. H. Smith
  0 siblings, 0 replies; 13+ messages in thread
From: Jacob M. H. Smith @ 2009-06-25 17:30 UTC (permalink / raw)


Everyone, thank you very much for all the tips, suggestion and sample
code.
I now have a much better idea on how to best approach the problem.

Best regards.
Jacob



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

end of thread, other threads:[~2009-06-25 17:30 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-23 21:06 GNAT.Sockets. Blocking? Jacob M. H. Smith
2009-06-24  0:14 ` John B. Matthews
2009-06-24  4:55   ` Jacob M. H. Smith
2009-06-24 14:36     ` John B. Matthews
2009-06-24  7:47 ` Dmitry A. Kazakov
2009-06-24 13:32 ` anon
2009-06-24 14:03 ` anon
2009-06-24 15:14 ` Pascal Obry
2009-06-24 18:44 ` Simple solution was " anon
2009-06-24 18:47 ` Per Sandberg
2009-06-24 19:51   ` Pascal Obry
2009-06-24 22:12   ` Jeffrey R. Carter
2009-06-25 17:30     ` Jacob M. H. Smith

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