Search code examples
socketsselectsml

How to use Socket.select


How do I go about using Socket.select in Standard ML?

According to the docs, I'm supposed to pass it three lists of sockets and a timeout option, and the function returns when any of the sockets are ready to do something (and I assume, but don't know for sure that the sockets in the out list are only the ones that need attention). However,

  1. The input seems to be neither a tuple, nor four arguments. How do I go about constructing an appropriate input structure?
  2. select takes and returns lists of sock_desc, and there doesn't seem to be a way of getting a socket back from its sock_desc. There also doesn't seem to be a way of constructing an efficient map, since it doesn't seem to be possible to order two sock_descs, merely compare them for equality. Once I've got the return value from select, how do I do anything useful with the returned sockets, such as write responses out, or call accept on them?

Solution

    1. The input argument is a record with four fields, so your code should look something like this:
    Socket.select {
      rds = readSocketDescs,
      wrs = writeSocketDescs,
      exs = exnSocketDescs,
      timeout = SOME (Time.fromSeconds 10)
    }
    
    1. Yeah, not sure, probably you need to keep a mapping yourself using lists. Not very efficient, but I can't see what else you can do.
    (**
     * Produces a list of all the pairs in `listPair`, whose keys are present
     * in `whiteList`. Example:
     *
     * ```sml
     * - filterListPair op= [(1,"a"), (2,"b"), (3,"c")] [2,3];
     * val it = [(2,"b"),(3,"c")] : (int * string) list
     * ```
     *)
    fun filterListPair eq listPair whiteList =
      let
        fun recur listPair whiteList result =
          case (listPair, whiteList) of
            ([], _) => result
          | (_, []) => result
          | ((x, y) :: xs, k :: ks) =>
              if eq (x, k)
              then recur xs ks ((x, y) :: result)
              else recur xs whiteList result
      in
        List.rev (recur listPair whiteList [])
      end
    
    val sockets = [ (* what have you *) ]
    val descsToSockets = List.map (fn s => (Socket.sockDesc s, s)) sockets
    val { rds, wrs, exs } = Socket.select {
      rds = readSocketDescs,
      wrs = writeSocketDescs,
      exs = exnSocketDescs,
      timeout = SOME (Time.fromSeconds 10)
    }
    
    (*
     * The contract of Socket.select ensures that the order in input lists
     * is preserved in the output lists, so we can use `filterListPair`.
     *)
    val selectedReadSockets =
      filterListPair Socket.sameDesc descsToSockets rds