指向性メモ::2005-12-19::Adaはselect()なんてセコいまねはしない

ページ情報
制作日
2005-12-19T19:27:06+09:00
最終更新日
2005-12-20T23:11:24+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

Name
YT
Datetime
2005-12-19T20:27:26+09:00
Message

おお、コンパイラ動作おめでとうございます!

Ada.Streams.ReadはTYPE'Readの下働きですので埋まるまで待つわけですね。上記コードであればCharacter'ReadとかString'Readでいいと思います。

待たない読み込みは確かめてませんが見た感じReceive_Socketじゃないでしょうか。selectも、Check_Selectorが該当しそうです。でもtaskのほうがらしいですよね、私も参考になります。

それでは、期待しております。

Name
石川
Datetime
2005-12-20T23:11:24+09:00
Message

おおお、アドバイスありがとうございます。

構文についてはだいぶ理解できてきたのですが、標準パッケージの内容が理解が必要なようです。

Javadocみたいにリファレンスが纏められてるといいんですが……。

Trackbacks

Trackback Ping URI

http://yudai.arielworks.com/memo/2005/12/19/192706.trackback

末尾に「6 + 2」の計算結果を繋げて下さい。例えば計算結果が「17」の場合、「192706.trackback17」です。これは機械的なトラックバックスパムを防止するための措置です。

Post a comment

Name (optional)
Email address or URI (optional)
Do the math below (required to filter comment spams)
6 + 2 + 9 =
Message (required)
Submit
連絡先、リンク、転載や複製などについては『サイト案内』をご覧ください。Powered by HIMMEL

I ♥ Validator