One way you might also solve this on UNIX systems is you could fork after 
listening on the socket. The file descriptor for the socket from the parent 
would then be shared with the children and so their accept calls would be "load 
balanced" by way of them all accepting connections from the same queue. This 
solves the problem without requiring SO_REUSEPORT (the disadvantage being that 
there's only a single kernel-level accept queue with this approach, whereas 
with SO_REUSEPORT each process would get its own queue). 

Is there a way to fork(2) in Racket?

On Sun, Nov 25th, 2018 at 10:51 AM, George Neuner <gneun...@comcast.net> wrote:

> 
> 
> 
> On 11/24/2018 7:39 PM, Philip McGrath wrote:
> 
> 
>> On Fri, Nov 23, 2018 at 5:44 PM George Neuner < 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.
>

-- 
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