Module Tcp.Server
A Server.t represents a TCP server listening on a socket.
val sexp_of_t : ('address -> Ppx_sexp_conv_lib.Sexp.t) -> ('listening_on -> Ppx_sexp_conv_lib.Sexp.t) -> ('address, 'listening_on) t -> Ppx_sexp_conv_lib.Sexp.t
type inet= (Async_extra__.Import.Socket.Address.Inet.t, int) t
val sexp_of_inet : inet -> Ppx_sexp_conv_lib.Sexp.t
type unix= (Async_extra__.Import.Socket.Address.Unix.t, string) t
val sexp_of_unix : unix -> Ppx_sexp_conv_lib.Sexp.t
val invariant : (_, _) t -> unitval listening_on : (_, 'listening_on) t -> 'listening_onval listening_on_address : ('address, _) t -> 'addressval close : ?close_existing_connections:bool -> (_, _) t -> unit Async_extra__.Import.Deferred.tclose tstarts closing the listening socket, and returns a deferred that becomes determined afterFd.close_finished fdon the socket'sfd. It is guaranteed thatt's client handler will never be called afterclose t. It is ok to callclosemultiple times on the samet; calls subsequent to the initial call will have no effect, but will return the same deferred as the original call.With
~close_existing_connections:true,closecloses the sockets of all existing connections.closedoes not (and cannot) stop the handlers handling the connections, but they will of course be unable to write to or read from the socket. The result ofclosebecomes determined when all the socket file descriptors are closed and the socket'sfdis closed.
val close_finished : (_, _) t -> unit Async_extra__.Import.Deferred.tclose_finishedbecomes determined afterFd.close_finished fdon the socket'sfd, i.e., the same deferred thatclosereturns.close_finisheddiffers fromclosein that it does not have the side effect of initiating a close.
val is_closed : (_, _) t -> boolis_closed treturnstrueiffclose thas been called.
val close_finished_and_handlers_determined : (_, _) t -> unit Async_extra__.Import.Deferred.tclose_finished_and_handlers_determined tbecomes determined afterclose_finished tis determined and the return of all active handlers is determined.
type ('address, 'listening_on, 'callback) create_options= ?max_connections:int -> ?max_accepts_per_batch:int -> ?backlog:int -> ?socket:([ `Unconnected ], 'address) Async_extra__.Import.Socket.t -> on_handler_error:[ `Raise | `Ignore | `Call of 'address -> exn -> unit ] -> ('address, 'listening_on) Where_to_listen.t -> 'callback -> ('address, 'listening_on) t Async_extra__.Import.Deferred.tOptions for server creation:
backlogis the number of clients that can have a connection pending, as withUnix.listen. Additional connections may be rejected, ignored, or enqueued anyway, depending on OS, version, and configuration.max_connectionsis the maximum number of clients that can be connected simultaneously. The server will not callacceptunless the number of clients is less thanmax_connections, although of course potential clients can have a connection pending.max_accepts_per_batchis the maximum number of connections that the server will retrieve per blockingUnix.accept call. Servers that must handle a large number of connections tend to observe a stall in connection accept rates when under heavy load. Increasingmax_accepts_per_batchwill ameliorate this effect, increasing connection accept rates and overall throughput at the cost of increased contention for resources amongst connections. Servers that are under light load or ones that only service a small number of connections at a time should see little to no difference in behavior for different values ofmax_accepts_per_branch.Supplying
socketcauses the server to usesocketrather than create a new socket. In this usage, creation does not setSocket.Opt.reuseaddrtotrue; if you want that, you must setreuseaddrbefore creation.on_handler_errordetermines what happens if the handler throws an exception. If an exception is raised by on_handler_error (either explicitly via`Raise, or in the closure passed to`Call) no further connections will be accepted.
val create_sock : ('address, 'listening_on, 'address -> ([ `Active ], 'address) Async_extra__.Import.Socket.t -> unit Async_extra__.Import.Deferred.t) create_optionscreate_sock where_to_listen handlerstarts a server listening to a socket as specified bywhere_to_listen. It returns a server once the socket is ready to accept connections. The server callshandler address socketfor each client that connects. If the deferred returned byhandleris ever determined, orhandlerraises an exception, thensocketis closed.The server will stop accepting and close the listening socket when an error handler raises (either via
`Raiseor`Call fwherefraises), or ifcloseis called.
val create : ?buffer_age_limit:Async_extra__.Import.Writer.buffer_age_limit -> ('address, 'listening_on, 'address -> Async_extra__.Import.Reader.t -> Async_extra__.Import.Writer.t -> unit Async_extra__.Import.Deferred.t) create_optionscreate where_to_listen handleris a convenience wrapper aroundcreate_sockthat pass a reader and writer for the client socket to the callback. If the deferred returned byhandleris ever determined, orhandlerraises an exception, then the reader and writer are closed.buffer_age_limitpasses on to the underlying writer option of the same name.
val listening_socket : ('address, _) t -> ([ `Passive ], 'address) Async_extra__.Import.Socket.tlistening_socket taccesses the listening socket, which should be used with care. An anticipated use is withAsync_udp.bind_to_interface_exn. Accepting connections on the socket directly will circumventmax_connectionsandon_handler_error, however, and is not recommended.
val num_connections : (_, _) t -> intval set_drop_incoming_connections : (_, _) t -> bool -> unitset_drop_incoming_connectionsconfigures whether each incoming connection will be immediately dropped or not. This is a hack to effectively get a "pause listening" feature. We can't reliably usebacklogandmax_num_connectionsto reject incoming connections. For example, if we reachmax_num_connections, we won't callacceptbut OS might still establish TCP connection. The client will see the connection as established but no data will be exchanged and we'd have to rely on TCP retransmit timeouts to close the connection. In many cases we would prefer to accept and then immediately close the connection. This is an intermediate solution until we do a more principled solution (but much more complicated) when we close the listening socket and then laterbindandlistenagain when we decide to unpause the server.drop_incoming_connectionsis set to false.