On 11/24/2018 7:39 PM, Philip McGrath wrote:
On Fri, Nov 23, 2018 at 5:44 PM George Neuner <[email protected] <mailto:[email protected]>> 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to