Adaはselect()なんてセコいまねはしない

というわけで、受信と送信を同時に行うプログラムを作ってみた。

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

with Ada.Streams;
use type Ada.Streams.Stream_Element_Count;

procedure Sock is

   task Connection_Send is
      entry Start (Connection : in out Stream_Access);
      entry Stop;
   end Connection_Send;

   task body Connection_Send is
      Connection_Stream : Stream_Access;
      Item              : String(1 .. 512);
      Last              : Natural;
   begin
      accept Start (Connection : in out Stream_Access) do
         Connection_Stream := Connection;
      end Start;
      loop
         Ada.Text_IO.Get_Line (Item => Item, Last => Last);
         String'Write(Connection_Stream, Item(1 .. Last) & ASCII.LF);
      end loop;
   end Connection_Send;

   task Connection_Recieve is
      entry Start (Connection : in out Stream_Access);
      entry Stop;
   end Connection_Recieve;

   task body Connection_Recieve is
      Connection_Stream : Stream_Access;
      Recieve        : Ada.Streams.Stream_Element_Array (1 .. 1);
      Recieve_Offset : Ada.Streams.Stream_Element_Count;
   begin
      accept Start (Connection : in out Stream_Access) do
         Connection_Stream := Connection;
      end Start;
      loop
         Ada.Streams.Read (Connection_Stream.all, Recieve, Recieve_Offset);
         exit when Recieve_Offset = 0;

         for I in 1 .. Recieve_Offset loop
            Ada.Text_IO.Put (Character'Val (Recieve (I)));
         end loop;
      end loop;
   end Connection_Recieve;

   Server         : Socket_Type;
   Server_Address : Sock_Addr_Type;
   Client         : Socket_Type;
   Clinet_Adress  : Sock_Addr_Type;
   Connection     : Stream_Access;

begin
      Initialize;
      Server_Address.Addr := Inet_Addr("127.0.0.1");
      Server_Address.Port := 9999;

      if Ada.Command_Line.Argument(1) = "-s" then
         Create_Socket (Server);
         Bind_Socket (Server, Server_Address);
         Listen_Socket (Server);
         Ada.Text_IO.Put_Line ("Listening...");
         Accept_Socket (Server, Client, Clinet_Adress);
         Close_Socket (Server); -- Stop listening
         Connection := Stream (Client);
      elsif Ada.Command_Line.Argument(1) = "-c" then
         Ada.Text_IO.Put_Line ("Connecting...");
         Create_Socket (Server);
         Connect_Socket (Server, Server_Address);
         Connection := Stream (Server);
      end if;

      Ada.Text_IO.Put_Line ("Connection Established.");
      Ada.Text_IO.Put_Line ("-----------------------");

      Connection_Recieve.Start(Connection);
      Connection_Send.Start(Connection);
end Sock;

sock.adbという名前で保存したら、gnatmake sock.adbでコンパイルできるはず。

実行ファイルが出来たら./sock -sでサーバとして起動し、localhostの9999番ポートでlistenする。つぎに./sock -cでクライアントが起動し、同じくlocalhostの9999番ポートに接続する。接続が済めば、それぞれのターミナルで入力した文字が相手側のターミナルに表示されるはずだ。終了処理を省いているので、停止はCtrl+Cで。

最初、AdaのselectをCのselect()と似た何かだと勘違いしていたため、やや混乱した。Adaの場合はselect()を使うよりも(そもそも、どこかにあるのだろうか)、Taskで並列処理されるのが一般的なようだ。