comp.lang.ada
 help / color / mirror / Atom feed
* Need help creating a multi client TCP server with Ada
@ 2014-02-06 21:42 alex.aanis
  2014-02-06 22:23 ` adambeneschan
  2014-02-07 18:34 ` Simon Wright
  0 siblings, 2 replies; 7+ messages in thread
From: alex.aanis @ 2014-02-06 21:42 UTC (permalink / raw)


Hi, 
Im new here and an Ada beginner. I have created a server/client TCP program which works nicely but the problem is I don't know how to accept more than one client. Code is on github: goo.gl/RvNIei

The server has 3 tasks. listener, writer, reader task.

--Listener task
--Listen for incoming connections
--Notify on client connect
--Save the new channel for future read and write access

Sockets.Accept_Socket(...)
channel := Sockets.Stream (Connection);
Put_Line ( Sockets.Image (Client) & " connected.");


I tried to create a doubly linked list which points to channel( GNAT.Sockets.Stream_Access ) using Ada.containers with out any luck! It seems that Ada.containers.double_linked_list cant be used with stream_access types.

1. How may I proceed with this? 
2. How can I know if one client has been disconnected?


Alex



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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-06 21:42 Need help creating a multi client TCP server with Ada alex.aanis
@ 2014-02-06 22:23 ` adambeneschan
  2014-02-06 23:40   ` alex.aanis
  2014-02-07 18:34 ` Simon Wright
  1 sibling, 1 reply; 7+ messages in thread
From: adambeneschan @ 2014-02-06 22:23 UTC (permalink / raw)


On Thursday, February 6, 2014 1:42:46 PM UTC-8, alex....@gmail.com wrote:

> I tried to create a doubly linked list which points to channel( GNAT.Sockets.Stream_Access ) using Ada.containers with out any luck! It seems that Ada.containers.double_linked_list cant be used with stream_access types.

Why not?  Are you getting an error like "no visible subprogram matches the specification for "=""?  If that's the case, try adding this before instantiating Doubly_Linked_List:

    use type GNAT.Sockets.Stream_Access;

                               -- Adam


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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-06 22:23 ` adambeneschan
@ 2014-02-06 23:40   ` alex.aanis
  2014-02-07  8:48     ` Jacob Sparre Andersen
  0 siblings, 1 reply; 7+ messages in thread
From: alex.aanis @ 2014-02-06 23:40 UTC (permalink / raw)


>     use type GNAT.Sockets.Stream_Access;
>                                -- Adam

Yes, I now can can store the channels. However I still can't connect more than one client. Is there  something wrong with my listener task:

 task body listenerTask is
  status      : Sockets.Selector_Status;
  Client      : Sockets.Sock_Addr_Type;
  Connection  : Sockets.Socket_Type;
  channel      : Sockets.Stream_Access;
  
 begin
  loop
   Sockets.Accept_Socket (
			  Server  => Receiver,
			  Socket  => Connection,
			  Address => Client,
			  timeout => 30.0,
			  Status  => status
			 );

   channel := Sockets.Stream (Connection);
   channels.Append (channel);

  end loop;
 end;

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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-06 23:40   ` alex.aanis
@ 2014-02-07  8:48     ` Jacob Sparre Andersen
  2014-02-07 17:16       ` alex.aanis
  0 siblings, 1 reply; 7+ messages in thread
From: Jacob Sparre Andersen @ 2014-02-07  8:48 UTC (permalink / raw)


alex.aanis@gmail.com writes:

> Yes, I now can can store the channels. However I still can't connect
> more than one client. Is there something wrong with my listener task:
>
>  task body listenerTask is
>   status      : Sockets.Selector_Status;
>   Client      : Sockets.Sock_Addr_Type;
>   Connection  : Sockets.Socket_Type;
>   channel      : Sockets.Stream_Access;
>   
>  begin
>   loop
>    Sockets.Accept_Socket (
> 			  Server  => Receiver,
> 			  Socket  => Connection,
> 			  Address => Client,
> 			  timeout => 30.0,
> 			  Status  => status
> 			 );
>
>    channel := Sockets.Stream (Connection);
>    channels.Append (channel);
>
>   end loop;
>  end;

It looks like it might work.  Have you set up your receiver correctly?
Where are the connections processed?  It appears that "Channels" is a
global variable.  Have you made sure to make it protected?

You may want to add an exception handler to your listener task for
reporting any exceptions in the task.

It would be nice if you could adhere to the style described in the Ada
Quality and Style Guide (indentation, labels after "end", identifiers).

Greetings,

Jacob
-- 
"Computer Science is to Science, as Plumbing is to Hydrodynamics"

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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-07  8:48     ` Jacob Sparre Andersen
@ 2014-02-07 17:16       ` alex.aanis
  2014-02-07 17:53         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 7+ messages in thread
From: alex.aanis @ 2014-02-07 17:16 UTC (permalink / raw)


On Friday, February 7, 2014 9:48:27 AM UTC+1, Jacob Sparre Andersen wrote:
> alex.aanis@gmail.com writes:
> 
> 
> 
> > Yes, I now can can store the channels. However I still can't connect
> 
> > more than one client. Is there something wrong with my listener task:
> 
> >
> 
> >  task body listenerTask is
> 
> >   status      : Sockets.Selector_Status;
> 
> >   Client      : Sockets.Sock_Addr_Type;
> 
> >   Connection  : Sockets.Socket_Type;
> 
> >   channel      : Sockets.Stream_Access;
> 
> >   
> 
> >  begin
> 
> >   loop
> 
> >    Sockets.Accept_Socket (
> 
> > 			  Server  => Receiver,
> 
> > 			  Socket  => Connection,
> 
> > 			  Address => Client,
> 
> > 			  timeout => 30.0,
> 
> > 			  Status  => status
> 
> > 			 );
> 
> >
> 
> >    channel := Sockets.Stream (Connection);
> 
> >    channels.Append (channel);
> 
> >
> 
> >   end loop;
> 
> >  end;
> 
> 
> 
> It looks like it might work.  Have you set up your receiver correctly?
> 
> Where are the connections processed?  It appears that "Channels" is a
> 
> global variable.  Have you made sure to make it protected?
> 
> 
> 
> You may want to add an exception handler to your listener task for
> 
> reporting any exceptions in the task.
> 
> 
> 
> It would be nice if you could adhere to the style described in the Ada
> 
> Quality and Style Guide (indentation, labels after "end", identifiers).
> 
> 
> 
> Greetings,
> 
> 
> 
> Jacob
> 
> -- 
> 
> "Computer Science is to Science, as Plumbing is to Hydrodynamics"



Thank you Jacob for replying. And thanks for the Ada style guidelines. Im at chapter 3 now. 
Could you please see my code here on Github: http://goo.gl/GaO2a3. The folder is called "TCP Communication". 

I've read about protected. But didn't quite understand it. How may I use protected types within a task?







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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-07 17:16       ` alex.aanis
@ 2014-02-07 17:53         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 7+ messages in thread
From: Dmitry A. Kazakov @ 2014-02-07 17:53 UTC (permalink / raw)


On Fri, 7 Feb 2014 09:16:03 -0800 (PST), alex.aanis@gmail.com wrote:

> I've read about protected. But didn't quite understand it. How may I use
> protected types within a task?

You certainly do not need protected objects for a server implementation.
Provided you are working using blocking sockets, once Accept_Socket returns
a new socket = accepts a new connections, you start a task and pass the
socket to it. The task then handles the connection. It also does the socket
shutdown and closes the socket when the session is completed.

Note that blocking sockets work up to a certain number of connections
because the maximal number of tasks (threads) is usually limited in the OS.
The maximal number of sockets is normally much higher. So if you have >100
clients would require a different design based on socket select. A
full-duplex blocking socket I/O requires 2 tasks per socket.

P.S. Regarding socket disconnect. You detect that when reading from the
socket returns 0 octets. When sending you get an error. Typically on either
read or write error or when you read 0 octets, you do socket shutdown,
close the socket and dispose the reader and writer tasks, assuming a
full-duplex communication, or the single I/O task if it is half-duplex.

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

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

* Re: Need help creating a multi client TCP server with Ada
  2014-02-06 21:42 Need help creating a multi client TCP server with Ada alex.aanis
  2014-02-06 22:23 ` adambeneschan
@ 2014-02-07 18:34 ` Simon Wright
  1 sibling, 0 replies; 7+ messages in thread
From: Simon Wright @ 2014-02-07 18:34 UTC (permalink / raw)


alex.aanis@gmail.com writes:

>           Code is on github: goo.gl/RvNIei

It'd be a Good Idea not to include the contents of your bin/ and obj/
directories in your checked-in items! They're useless to anyone who
clones the repo (unless they're running the same OS and compiler as you,
of course, but that's unlikely).

gnatmake's -p switch is your friend (create any needed directories if
necessary).

Actually I see you have obj/doc/, shouldn't that be just doc/?

Looking at TCP.Server.Client_Type (in V2), you have

   task body Client_Type is
      Stream : Sockets.Stream_Access;
   begin
     loop

      accept Set_Stream (S : in Sockets.Stream_Access) do
        Stream := S;
      end Set_Stream;

      accept Write (Message : in String) do
         String'Output ( Stream, Message );
      end Write;

      accept Read (Message : out String) do
         Message := String'Input ( Stream );
      end Read;

     end loop;
   end Client_Type;

which won't do what you want; every pass through the loop the task waits
for a call on Set_Stream, then on Write ... you need something more like

   task body Client_Type is
      Stream : Sockets.Stream_Access;
   begin
      --  Must have a stream before anything else
      accept Set_Stream (S : in Sockets.Stream_Access) do
        Stream := S;
      end Set_Stream;
      loop
         select
            accept Write (Message : in String) do
               String'Output ( Stream, Message );
            end Write;
         or
            accept Read (Message : out String) do
               Message := String'Input ( Stream );
            end Read;
         end select;
      end loop;
   end Client_Type;

> 2. How can I know if one client has been disconnected?

If you try to write to it and get a Socket_Error; or if you try to read
from it and get a successful completion with zero bytes read (or, of
course, a Socket_Error; but I think that'll only happen if you've closed
the server end).

Q. How do you know whether to try to read from the socket?
A. Use GNAT.Sockets.Selector_Type and Check_Selector().


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

end of thread, other threads:[~2014-02-07 18:34 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-06 21:42 Need help creating a multi client TCP server with Ada alex.aanis
2014-02-06 22:23 ` adambeneschan
2014-02-06 23:40   ` alex.aanis
2014-02-07  8:48     ` Jacob Sparre Andersen
2014-02-07 17:16       ` alex.aanis
2014-02-07 17:53         ` Dmitry A. Kazakov
2014-02-07 18:34 ` Simon Wright

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