On 11/24/2018 7:39 PM, Philip McGrath wrote:
On Fri, Nov 23, 2018 at 5:44 PM George Neuner <gneun...@comcast.net <mailto:gneun...@comcast.net>> wrote:

    Multiple (identical) server instances running on the same machine
    can listen for connections on the same network port - an incoming
    client call will be connected to only one of them.  You only need
    to use different ports when services are not interchangeable [i.e.
    it matters which one you are talking to].

    Process parallelism, in effect, can give you automatic connection
    load balancing on a single machine.  Using a separate load
    balancer in front technically is overkill for such situations, but
    it is a good design if you want to preserve the option to relocate
    your services to different machines.


I didn't know this, and it sounds useful! Unfortunately, this functionality doesn't currently seem to be exposed at the Racket level. This example program:

#lang racket

(provide launch-places)

(module+ main
  (launch-places))

(define (launch-places [port 8011])
  (define place-log-pch
    (let-values ([{in-pch place-log-pch} (place-channel)])
      (thread (λ ()
                (let loop ()
                  (write-string (place-channel-get in-pch))
                  (loop))))
      place-log-pch))
  (define workers
    (for/list ([n (in-range 0 2)])
      (place/context p
        (define (place-log msg)
          (place-channel-put place-log-pch
                             (format "Place ~a: ~a\n" n msg)))
        (parameterize
            ([error-display-handler (λ (s v) (place-log s))])
          (place-log "started")
          (define listener
            (tcp-listen port 4 'reuse))
          (place-log "created listener")
          ;; don't let listener be gc-ed
          (tcp-accept listener)
          (place-log "ended")))))
  (apply sync (map place-dead-evt workers))
  (for-each place-kill workers))

prints the following output on both Mac OS and Ubuntu:
Place 0: started
Place 0: created listener
Place 1: started
Place 1: tcp-listen: listen failed
  port number: 8011
  system error: Address already in use; errno=48

It looks like the `reuse?` argument to `tcp-listen` corresponds to `SO_REUSEADDR` rather than `SO_REUSEPORT`. That's consistent with what `udp-bind!` explicitly says it does, and its the only thing I can see happening in the implementation (https://github.com/racket/racket/blob/master/racket/src/rktio/rktio_network.c)

It seems like this might be a useful feature in Racket, but I'm not sure of what would be needed to expose it in a good way. In particular, some quick Googling revealed that there are some portability considerations, which I haven't fully digested yet (https://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t).

-Philip



It's not working because the places in this code are OS threads in the SAME process.  You need to start separate processes:  using *dynamic-place* targeting localhost, or using *system*, *process*, *subprocess*, etc.

AIUI  'reuse?'  sets both  SO_REUSEADDR  and SO_REUSEPORT.  But a single process can't open the same port twice.

George

--
You received this message because you are subscribed to the Google Groups "Racket 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to