Skip to content

Instantly share code, notes, and snippets.

@tkob
Last active September 23, 2018 01:08
Show Gist options
  • Select an option

  • Save tkob/7725f5a08f155294cf510aaf400c4ee3 to your computer and use it in GitHub Desktop.

Select an option

Save tkob/7725f5a08f155294cf510aaf400c4ee3 to your computer and use it in GitHub Desktop.
SML Socket.select example
val _ = main ()
Library
structure SocketSelect
is
$/basis.cm
socketselect.sml
$(SML_LIB)/basis/basis.mlb
socketselect.sml
boot.sml
structure SocketSelect = struct
fun socketFromAddr (host, port) =
case NetHostDB.fromString host of
SOME host =>
let
val addr = INetSock.toAddr (host, port)
val sock = INetSock.UDP.socket ()
in
Socket.bind (sock, addr);
sock
end
| NONE => raise Fail ("host " ^ host ^ " not found")
fun socketFromPath path =
let
val addr = UnixSock.toAddr path
(* Pre-condition: the Unix domain socket is not in use.
Otherwise, bind will fail. *)
fun create path =
let
val sock = UnixSock.DGrm.socket ()
val _ = Socket.bind (sock, addr)
in
sock
end
in
if OS.FileSys.access (path, [])
then
let
exception InUse
in
(ignore (Socket.connectNB (UnixSock.DGrm.socket (), addr)); raise InUse)
handle
OS.SysErr (_, _) =>
(* if connect raises an exception,
the socket is not used and it can be safely removed *)
(OS.FileSys.remove path; create path)
| InUse =>
(* else, someone else is using the socket *)
raise OS.SysErr ("\"" ^ path ^ "\" already in use", NONE)
end
else
create path
end
fun main (name : string, argv : string list) =
let
val domainSock = socketFromPath "log"
val udpSock = socketFromAddr ("0.0.0.0", 5140)
fun readAndPrint sock =
let
val (vec, _) = Socket.recvVecFrom (sock, 1024)
val s = Byte.bytesToString vec
in
print (s ^ "\n")
end
type handler = { sockDesc : Socket.sock_desc, handler : unit -> unit }
val handlers = [
{ sockDesc = Socket.sockDesc domainSock, handler = fn () => readAndPrint domainSock},
{ sockDesc = Socket.sockDesc udpSock, handler = fn () => readAndPrint udpSock}]
val descs = map #sockDesc handlers
fun loop () =
let
val {rds, wrs, exs} =
Socket.select {rds = descs, wrs = [], exs = [], timeout = NONE}
fun g rd =
let
fun f {sockDesc, handler} =
if Socket.sameDesc (rd, sockDesc)
then handler ()
else ()
in
List.app f handlers
end
in
List.app g rds;
loop ()
end
in
loop ();
OS.Process.success
end
end
fun main () =
OS.Process.exit (SocketSelect.main (CommandLine.name (), CommandLine.arguments ()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment