task typeとnewを使うと良いらしい
Taskの開始タイミングはtask type
とnew
を使うと上手くコントロールできるらしい。
要点だけまとめると次のような感じ。
procedure Sock is
-- Taskを作る
task type Connection_Send_Task is
entry Start (Connection : in out Stream_Access);
end Connection_Send_Task;
--- Taskの処理内容
task body Connection_Send_Task is
...
begin
...
accept Start (Connection : in out Stream_Access) do
Connection_Stream := Connection;
end Start;
...
end Connection_Send_Task;
-- TaskをTypeとして定義する
type Connection_Send_Type is access Connection_Send_Task;
-- そのタイプの変数を作る
Connection_Send : Connection_Send_Type;
begin
...
-- Taskの制作
Connection_Send := new Connection_Send_Task;
-- 処理開始
Connection_Send.Start(Connection);
...
end Sock;
とりあえず、is access
が謎なので、そこら辺を解明しないと気持ちよく使うことは出来なさそう。TypeとSubTypeも今一理解できてないし。Taskに関してはリファレンスマニュアルの9章あたりを読むと大体理解できそうな雰囲気。
一応コード全体も掲載しておこう。
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; use Ada.Command_Line;
with Ada.Streams;
use type Ada.Streams.Stream_Element_Count;
procedure Sock is
task type Connection_Send_Task is
entry Start (Connection : in out Stream_Access);
entry Stop;
end Connection_Send_Task;
task body Connection_Send_Task 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
select
Ada.Text_IO.Get_Line (Item => Item, Last => Last);
String'Write(Connection_Stream, Item(1 .. Last) & ASCII.LF);
end loop;
end Connection_Send_Task;
task type Connection_Recieve_Task is
entry Start (Connection : in out Stream_Access);
entry Stop;
end Connection_Recieve_Task;
task body Connection_Recieve_Task is
Connection_Stream : Stream_Access;
Item : Character;
begin
accept Start (Connection : in out Stream_Access) do
Connection_Stream := Connection;
end Start;
loop
Character'Read (Connection_Stream, Item);
Ada.Text_IO.Put (Item);
end loop;
end Connection_Recieve_Task;
Server_Name : Unbounded_String;
Server_Port : Natural := 6667;
Server_Socket : Socket_Type;
Server_Address : Sock_Addr_Type;
Connection : Stream_Access;
type Connection_Send_Type is access Connection_Send_Task;
type Connection_Recieve_Type is access Connection_Recieve_Task;
Connection_Send : Connection_Send_Type;
Connection_Recieve : Connection_Recieve_Type;
begin
-- Parse arguments
if Argument_Count < 1 then
Put_Line ("Usage: " & Command_Name & " [-p port] hostname[:port]");
return;
else
for I in Integer range 1 .. Argument_Count loop
if Argument (I) = "-p" and I + 1 <= Argument_Count then
Server_Port := Integer'Value (Argument (I));
else
Server_Name := To_Unbounded_String(Argument (I));
end if;
end loop;
end if;
Server_Address.Addr := Addresses(Get_Host_By_Name(To_String(Server_Name)), 1);
Server_Address.Port := Port_Type(Server_Port);
Create_Socket (Server_Socket);
Ada.Text_IO.Put_Line ("Connecting...");
Connect_Socket (Server_Socket, Server_Address);
Connection := Stream (Server_Socket);
Ada.Text_IO.Put_Line ("Connection Established.");
Ada.Text_IO.Put_Line ("-----------------------");
Connection_Recieve := new Connection_Recieve_Task;
Connection_Send := new Connection_Send_Task;
Connection_Recieve.Start(Connection);
Connection_Send.Start(Connection);
end Sock;