%%% $Id: echo.oz,v 1.0 2002/11/05 12:26:00 dada Exp $
%%% http://dada.perl.it/shootout/
%%%
%%% contributed by Isaac Gouy
%% Usage: start from command line with
%% ozc -x echo.oz -o echo.oz.exe
%% echo.oz.exe 100000
functor
import System Application Open OS
define
Data = "Hello there sailor\n"
proc {ServerThread Sock SPort Bytes}
Sock = {New Open.socket server(port:SPort)}
{ServerLoop Sock 0 Bytes}
{Sock shutDown(how: [receive send])}{Sock close}
end
proc {ServerLoop Sock Sum Bytes}
local Message NewSum DR DW CR ST in
%% low-level Selects seem ~6% faster total
{Sock getDesc(DR DW)}{OS.readSelect DR}
{OS.read DR 1024 Message nil CR}
%% {Sock read(list: Message)} %% normal read
if Message == nil then %% connection has been closed
Bytes = Sum
else
NewSum = {Length Message} + Sum
{OS.writeSelect DW}{OS.write DW Message ST}
%% {Sock write(vs: Message)} %% normal write
{ServerLoop Sock NewSum Bytes}
end
end
end
proc {ClientThread SPort N}
local Sock in
Sock = {New Open.socket client(port:SPort)}
{ClientLoop Sock N}
{Sock shutDown(how: [receive send])}{Sock close}
end
end
proc {ClientLoop Sock N}
local Message DR DW CR ST in
if N > 0 then
{Sock getDesc(DR DW)}
{OS.writeSelect DW}{OS.write DW Data ST}
{OS.readSelect DR}{OS.read DR 1024 Message nil CR}
%% {Sock write(vs: Data)} %% normal write
%% {Sock read(list: Message)} %% normal read
if Message == Data then {ClientLoop Sock N-1} end
end
end
end
in
local Args A1 A2 A3 Socket SPort Bytes ArgList Pid in
Args = {Application.getArgs plain}
if {Length Args} == 1 then
%% We are the server process
A3|nil = Args
thread {ServerThread Socket SPort Bytes} end
%% Prepare to fork an OS process for the client
%% automatically close cmd.exe
%% start echo.oz.exe
%% pass a flag indicating the client process
%% pass the open server port SPort
%% pass the number of times the client should send the data
ArgList = ["/C" "echo.oz.exe" "client" {IntToString SPort} A3]
Pid = {New Open.pipe init(cmd: "cmd.exe" args: ArgList)}
%% Synchronize with server thread completion and indirectly with
%% the client process. Wait here until the dataflow variable Bytes
%% has been given a value in the server thread. That happens after
%% the client process closes the socket connection, when the client
%% process has sent all it's data and received all the replies.
{System.showInfo 'server processed '#{IntToString Bytes}#' bytes'}
elseif {Length Args} == 3 then
%% We are the client process
%% Take the flag, server port, times-to-repeat from the args
%% and use the main thread for the client
A1|A2|A3|nil = Args
if A1 == "client" then
{ClientThread {StringToInt A2} {StringToInt A3}}
end
end
end
{Application.exit 0}
end