指向性メモ::2005-12-19

ページ情報
制作日
2005-12-19T02:08:51+09:00
最終更新日
2005-12-20T23:11:24+09:00

復活のAda

Created:
2005-12-19T02:08:51+09:00

ある程度環境が整ったので、世界最強言語と評判のAdaを使用したプログラミングを再開してみる。

とりあえず、Socketを使って通信でもしてみようと思い、GNAT.Socketsについて調べてみる。が、しかし、さすがはAda、日本語の情報が皆無である。

あきらめて英語の情報を探していると、GNAT.Socketsを使ったコードのサンプルがあったので、改造してサーバのような何かを作ってみた。ちなみに、WikibooksのAdaに関するページの1部らしい。纏まっているので便利だ。

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

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

procedure Sock is

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

   Send   : String := (1 => ASCII.CR, 2 => ASCII.LF,
                       3 => ASCII.CR, 4 => ASCII.LF);
   Offset : Ada.Streams.Stream_Element_Count;
   Data   : Ada.Streams.Stream_Element_Array (1 .. 1);

begin

   Initialize;
   Create_Socket (Server);
   Server_Address.Addr := Inet_Addr("127.0.0.1");
   Server_Address.Port := 8000;

   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
   Channel := Stream (Client);

   loop
      Ada.Streams.Read (Channel.all, Data, Offset);
      exit when Offset = 0;
      for I in 1 .. Offset loop
         Ada.Text_IO.Put (Character'Val (Data (I)));
      end loop;
   end loop;

end Sock;

このコードで、TCPのポート8000でListenする。接続後は受信したデータを標準出力に表示してくれる。

Socket自体の使用方法はCと同一なのでそれほど難しくないのだが、リファレンスがろくにないのが何とも困る。

さて、Adaを勉強中の私はIOが理解できていない。Streams.Read()は第2引数のAda.Streams.Stream_Element_Array (size)が満杯になるまでバッファリングしてくれるようなのだが、用途によってはこれは好ましくない。上記のコードでは配列のサイズを1 .. 1として、1バイトごとに処理してるのだが、これは何か違う気がする。Direct_IOあたりを使うのが正しいのだろうか。

Adaはselectが言語構造に組み込まれているらしいので、次はそこら辺を弄ってみたい。が、その前に基本的なところをもう少し押さえる必要がありそうだ。

Comments
0
Trackbacks
0
PermaLink
http://yudai.arielworks.com/memo/2005/12/19/020851

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

Created:
2005-12-19T19:27:06+09:00

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

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で並列処理されるのが一般的なようだ。

Comments
2
Trackbacks
0
PermaLink
http://yudai.arielworks.com/memo/2005/12/19/192706
連絡先、リンク、転載や複製などについては『サイト案内』をご覧ください。Powered by HIMMEL

I ♥ Validator