Last active
September 23, 2018 01:08
-
-
Save tkob/7725f5a08f155294cf510aaf400c4ee3 to your computer and use it in GitHub Desktop.
SML Socket.select example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| val _ = main () |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Library | |
| structure SocketSelect | |
| is | |
| $/basis.cm | |
| socketselect.sml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $(SML_LIB)/basis/basis.mlb | |
| socketselect.sml | |
| boot.sml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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