ENet API
This CHICKEN module exposes a binding to the ENet network library for Scheme.
Synopsis
(import enet) ;; Client side (define host (make-host)) (define peer (host-connect host #:address "localhost" #:port 1234)) (let loop () (let ([event (host-service host 3)]) (if event (case (car event) [(connect) (when (equal? (cadr event) peer) (peer-send peer "Hello world!" #:flags '(reliable))) (loop)] [(receive) (when (equal? (cadr event) peer) (display (packet->string (cadddr event))) (newline) (peer-disconnect peer)) (loop)] [(disconnect) (unless (equal? (cadr event) peer) (loop))]) (begin (print "... waiting ...") (loop))))) ;; Server side (define host (make-host #:port 1234 #:max-peers 8)) (let loop () (let ([event (host-service host 3)]) (when event (case (car event) [(connect disconnect) => (lambda (kind) (let ([peer (cadr event)] [data (caddr event)]) (print kind " -- peer: " peer ", data: " data)))] [(receive) (let ([peer (cadr event)] [channel (caddr event)] [packet (cadddr event)]) (print "receive -- peer: " peer ", channel: " channel) (peer-send peer (string-append "echo: " (packet->string packet)) #:flags (packet-flags packet) #:channel channel))])) (loop)))
Host Management
(host? [v any/c]) → boolean?
Check whether a value is an ENet host.
(make-host #!key [address (or/c string? address-info? #f)] [port (or/c integer? #f)] [numeric? boolean?] [max-peers integer?] [channels integer?] [incoming integer?] [outgoing integer?]) → host?
Create a new ENet host at some network endpoint.
If address
is not specified or #f
, the procedure creates a host bound to a random network endpoint, suitable for use by a client.
If address
is a host name or IP address and port
a port number, or if address
is an address-info
object, the procedure creates a host bound to the specified network endpoint, suitable for use by a server. The numeric?
argument is internally passed to the address-infos
lookup function.
For a server host, max-peers
would also normally be set to a value larger than one, which is the default.
The number of channels
can be limited to a specific number or left at the maximum the library can support.
The incoming
and outgoing
network bandwidth can be limited to specific numbers of bytes/second or left unlimited.
(host-channels-limit! [host host?] #!optional [channels integer?]) → void?
Limit the maximum allowed channels of future incoming connections. If channels
is not given, the limit is reset to the maximum the library can support.
(host-bandwidth-limit! [host host?] #!key [incoming integer?] [outgoing integer?]) → void?
Limit the bandwidth used by a host. If the incoming
and/or outgoing
network bandwidth are not given, the corresponding limit is removed.
(host-compress! [host host?] #!optional [compression symbol?]) → void?
Set the packet compression algorithm for the host. If the compression
argument is omitted or the symbol 'range-coder
, the default range coder is used for compression. If the argument is set to #f
, no compression is used. Other options are currently not supported by this API.
Peer Management
(peer? [v any/c]) → boolean?
Check whether a value is an ENet peer.
(host-connect [host host?] #!key [address (or/c string? address-info? #f)] [port (or/c integer? #f)] [numeric? boolean?] [channels integer?] [cookie integer?]) → peer?
When address
is a host name or IP address and port
a port number, or when address
is an address-info
object, the procedure creates a new connection to the specified network endpoint. The numeric?
argument is internally passed to the address-infos
lookup function.
The number of channels
requested for the connection can be specified explicitly but defaults to 1.
A numerical cookie
may be passed to the server in the connection request.
(peer-disconnect [peer peer?] #!key [cookie integer?] [mode (or/c now later #f)]) → void?
Terminate communication with the given remote peer.
A numerical cookie
may be passed to the server in the disconnect notification.
The mode
argument controls how the connection is closed:
'now
- The connection is immediately abandoned. No notification is sent and the server will only notice termination through a timeout.
'later
- All pending packets for the connection are processed, then a disconnect notification is sent to the server. This procedure does not wait for connection termination, which will happen during a future call to
host-service
. #f
- Pending packets for the connection are discarded, but a disconnect notification is sent to the server. This procedure does not wait for connection termination, which will happen during a future call to
host-service
. This is the default behaviour.
(peer-address [peer peer?]) → address-info?
Retrieve an address-info
object representing the network endpoint of the given remote peer.
(peer-channels [peer peer?]) → integer?
Retrieve the number of channels allocated for communication with the given remote peer.
(peer-bandwidth [peer peer?]) → (values/c integer? integer?)
Retrieve the current bandwidth statistics for communication with the given remote peer. Returns two values representing the average number of incoming and outgoing bytes/second.
(peer-packet-loss [peer peer?]) → rational?
Retrieve the current packet loss quota for communication with the given remote peer.
(peer-round-trip-time [peer peer?]) → real?
Retrieve the current mean packet roundtrip time in fractional seconds for communication with the given remote peer.
(peer-ping [peer peer?]) → void?
Send a ping to the given remote peer to keep the connection alive. Usually it is not necessary to invoke this procedure manually as pings are sent out automatically in regular intervals during calls to host-service
i f there is no data traffic.
(peer-ping-interval! [peer peer?] #!optional [interval real?]) → void?
Set the automatic ping interval for the given remote peer. The interval may be given as a fractional number of seconds. If no interval is specified, the library reverts to its automatic behaviour.
Packet Management
(packet? [v any/c]) → boolean?
Check whether a value is an ENet packet.
(make-packet [data (or/c string? u8vector? blob?)] #!optional [flags list?]) → packet?
Create a new ENet packet. Since peer-send
and host-broadcast
also accept packet data and flags directly for implicit conversion, it will often not be necessary to create a packet explicitly.
The data
represented by the packet can be given as a string, byte vector or blob object. Note that the packet shares the underlying data storage with the scheme object!
The optional list of flags
can contain any of the following symbols:
'reliable
- Unreliable delivery is acceptable for the packet.
'unsequenced
- Out of sequence delivery is acceptable for the packet.
'unreliable-fragment
- If the packet has to be split into multiple fragments, unreliable delivery is acceptable for the fragments.
(packet-flags [packet packet?]) → list?
Retrieve the flags set for a given packet. The resulting list can contain any of the following symbols:
'reliable
- Unreliable delivery is acceptable for the packet.
'unsequenced
- Out of sequence delivery is acceptable for the packet.
'no-allocate
- Memory management for the packet's data content is handled outside the ENet library.
'unreliable-fragment
- If the packet has to be split into multiple fragments, unreliable delivery is acceptable for the fragments.
'sent
- The packet has been sent from all queues it has been entered into.
(packet-length [packet packet?]) → integer?
Retrieve the number of data bytes contained in the given packet.
(packet-null? [packet packet?]) → boolean?
Check whether the given packet has empty data content.
(packet->string [packet packet?]) → string?
Convert the data content of the given packet into a string.
(packet->u8vector [packet packet?]) → u8vector?
Convert the data content of the given packet into a byte vector.
(packet->blob [packet packet?]) → blob?
Convert the data content of the given packet into a blob object.
(packet-input-port [packet packet?]) → input-port?
Create a new input port that reads from the data content of the given packet.
(call-with-input-packet [packet packet?] [read (-> input-port? T)] #!key [partial? boolean?] [null? boolean?]) → T
Create a new input port that reads from the data content of the given packet, then call the given reader procedure on that port. Returns whatever the reader procedure returns, but signals an error if the packet was not fully consumed or an end of file object was returned (unless instructed not to do so).
If partial?
is given and not #f
, no error is signalled if the packet was not fully consumed by the reader procedure.
If null?
is given and not #f
, no error is signalled if the reader returned an end of file object.
(with-input-from-packet [packet packet?] [read (-> T)] #!key [partial? boolean?] [null? boolean?]) → T
Create a new input port that reads from the data content of the given packet, then call the given reader procedure with no arguments in a dynamic environment where current-input-port
is bound to that port. Returns whatever the reader procedure returns, but signals an error if the packet was not fully consumed or an end of file object was returned (unless instructed not to do so).
If partial?
is given and not #f
, no error is signalled if the packet was not fully consumed by the reader procedure.
If null?
is given and not #f
, no error is signalled if the reader returned an end of file object.
Communication Functions
(host-service [host host?] [timeout real?]) → (or/c list? #f)
Wait for events on the given host and shuttle packets between the host and its peers. This procedure will block for up to timeout
fractional seconds and return one pending event, if any.
The events returned from this procedure have one of the following forms:
(connect PEER COOKIE)
(disconnect PEER COOKIE)
- A peer has connected or disconnected from this host.
PEER
is an ENet peer object, and theCOOKIE
is the number passed tohost-connect
orpeer-disconnect
respectively. (receive PEER CHANNEL PACKET)
- A peer has sent a packet to this host.
PEER
is an ENet peer object,CHANNEL
is the channel number passed topeer-send
orhost-broadcast
, andPACKET
is a packet object containing the data and flags.
(peer-send [peer peer?] [data (or/c packet? string? u8vector? blob?)] #!key [flags list?] [channel integer?]) → packet?
Queue a packet to be sent to the given remote peer. If the given data
is not already a packet object, (make-packet data flags)
is implicitly invoked to form a new packet. The procedure returns the packet that will be sent.
Optionally, the number of the channel on which the packet should be sent can be specified.
It is possible to determine whether the packet has already been sent by inspecting its flags.
(host-broadcast [host host?] [data (or/c packet? string? u8vector? blob?)] #!key [flags list?] [channel integer?]) → packet?
Queue a packet to be sent to all remote peers connected to the given host. If the given data
is not already a packet object, (make-packet data flags)
is implicitly invoked to form a new packet. The procedure returns the packet that will be sent.
Optionally, the number of the channel on which the packet should be sent can be specified.
It is possible to determine whether the packet has already been sent by inspecting its flags.
(host-flush [host host?]) → void?
Immediately sends all packets queued on the given host to their target remote peers. Usually it is not necessary to invoke this procedure manually as packets are dispatched automatically during calls to host-service
.