14.3 Networking
14.3.1 TCP
14.3.2 UDP
On this page:
tcp-listen
tcp-connect
tcp-connect/ enable-break
tcp-accept
tcp-accept/ enable-break
tcp-accept-ready?
tcp-close
tcp-listener?
tcp-accept-evt
tcp-abandon-port
tcp-addresses
tcp-port?
14.3.1 TCP

The bindings documented in this section are provided by the racket/tcp and racket libraries, but not racket/base.

For information about TCP in general, see TCP/IP Illustrated, Volume 1 by W. Richard Stevens.

(tcp-listen port-no    
  [max-allow-wait    
  reuse?    
  hostname])  tcp-listener?
  port-no : 
(and/c exact-nonnegative-integer?
       (integer-in 0 65535))
  max-allow-wait : exact-nonnegative-integer? = 4
  reuse? : any/c = #f
  hostname : (or/c string? #f) = #f
Creates a “listening” server on the local machine at the port number specified by port-no. If port-no is 0 the socket binds to an ephemeral port, which can be determined by calling tcp-addresses. The max-allow-wait argument determines the maximum number of client connections that can be waiting for acceptance. (When max-allow-wait clients are waiting acceptance, no new client connections can be made.)

If the reuse? argument is true, then tcp-listen will create a listener even if the port is involved in a TIME_WAIT state. Such a use of reuse? defeats certain guarantees of the TCP protocol; see Stevens’s book for details. Furthermore, on many modern platforms, a true value for reuse? overrides TIME_WAIT only if the listener was previously created with a true value for reuse?.

If hostname is #f (the default), then the listener accepts connections to all of the listening machine’s addresses. Otherwise, the listener accepts connections only at the interface(s) associated with the given hostname. For example, providing "127.0.0.1" as hostname creates a listener that accepts only connections to "127.0.0.1" (the loopback interface) from the local machine.

(Racket implements a listener with multiple sockets, if necessary, to accomodate multiple addresses with different protocol families. Under Linux, if hostname maps to both IPv4 and IPv6 addresses, then the behavior depends on whether IPv6 is supported and IPv6 sockets can be configured to listen to only IPv6 connections: if IPv6 is not supported or IPv6 sockets are not configurable, then the IPv6 addresses are ignored; otherwise, each IPv6 listener accepts only IPv6 connections.)

The return value of tcp-listen is a TCP listener. This value can be used in future calls to tcp-accept, tcp-accept-ready?, and tcp-close. Each new TCP listener value is placed into the management of the current custodian (see Custodians).

If the server cannot be started by tcp-listen, the exn:fail:network exception is raised.

(tcp-connect hostname    
  port-no    
  [local-hostname    
  local-port-no])  
input-port? output-port?
  hostname : string?
  port-no : 
(and/c exact-nonnegative-integer?
      (integer-in 1 65535))
  local-hostname : (or/c string? #f) = #f
  local-port-no : 
(or/c (and/c exact-nonnegative-integer?
             (integer-in 1 65535))
      #f)
 = #f
Attempts to connect as a client to a listening server. The hostname argument is the server host’s Internet address name, and port-no is the port number where the server is listening.

(If hostname is associated with multiple addresses, they are tried one at a time until a connection succeeds. The name "localhost" generally specifies the local machine.)

The optional local-hostname and local-port-no specify the client’s address and port. If both are #f (the default), the client’s address and port are selected automatically. If local-hostname is not #f, then local-port-no must be non-#f. If local-port-no is non-#f and local-hostname is #f, then the given port is used but the address is selected automatically.

Two values are returned by tcp-connect: an input port and an output port. Data can be received from the server through the input port and sent to the server through the output port. If the server is a Racket program, it can obtain ports to communicate to the client with tcp-accept. These ports are placed into the management of the current custodian (see Custodians).

Initially, the returned input port is block-buffered, and the returned output port is block-buffered. Change the buffer mode using file-stream-buffer-mode.

Both of the returned ports must be closed to terminate the TCP connection. When both ports are still open, closing the output port with close-output-port sends a TCP close to the server (which is seen as an end-of-file if the server reads the connection through a port). In contrast, tcp-abandon-port (see below) closes the output port, but does not send a TCP close until the input port is also closed.

Note that the TCP protocol does not support a state where one end is willing to send but not read, nor does it include an automatic message when one end of a connection is fully closed. Instead, the other end of a connection discovers that one end is fully closed only as a response to sending data; in particular, some number of writes on the still-open end may appear to succeed, though writes will eventually produce an error.

If a connection cannot be established by tcp-connect, the exn:fail:network exception is raised.

(tcp-connect/enable-break hostname 
  port-no 
  [local-hostname] 
  local-port-no) 
  
input-port? output-port?
  hostname : string?
  port-no : 
(and/c exact-nonnegative-integer?
      (integer-in 1 65535))
  local-hostname : (or/c string? #f) = #f
  local-port-no : 
(or/c (and/c exact-nonnegative-integer?
             (integer-in 1 65535))
      #f)
Like tcp-connect, but breaking is enabled (see Breaks) while trying to connect. If breaking is disabled when tcp-connect/enable-break is called, then either ports are returned or the exn:break exception is raised, but not both.

(tcp-accept listener)  
input-port? output-port?
  listener : tcp-listener?
Accepts a client connection for the server associated with listener. If no client connection is waiting on the listening port, the call to tcp-accept will block. (See also tcp-accept-ready?.)

Two values are returned by tcp-accept: an input port and an output port. Data can be received from the client through the input port and sent to the client through the output port. These ports are placed into the management of the current custodian (see Custodians).

In terms of buffering and connection states, the ports act the same as ports from tcp-connect.

If a connection cannot be accepted by tcp-accept, or if the listener has been closed, the exn:fail:network exception is raised.

Like tcp-accept, but breaking is enabled (see Breaks) while trying to accept a connection. If breaking is disabled when tcp-accept/enable-break is called, then either ports are returned or the exn:break exception is raised, but not both.

(tcp-accept-ready? listener)  boolean?
  listener : tcp-listener?
Tests whether an unaccepted client has connected to the server associated with listener. If a client is waiting, the return value is #t, otherwise it is #f. A client is accepted with the tcp-accept procedure, which returns ports for communicating with the client and removes the client from the list of unaccepted clients.

If the listener has been closed, the exn:fail:network exception is raised.

(tcp-close listener)  void?
  listener : tcp-listener?
Shuts down the server associated with listener. All unaccepted clients receive an end-of-file from the server; connections to accepted clients are unaffected.

If the listener has already been closed, the exn:fail:network exception is raised.

The listener’s port number may not become immediately available for new listeners (with the default reuse? argument of tcp-listen). For further information, see Stevens’s explanation of the TIME_WAIT TCP state.

(tcp-listener? v)  boolean?
  v : any/c
Returns #t if v is a TCP listener created by tcp-listen, #f otherwise.

(tcp-accept-evt listener)  evt?
  listener : tcp-listener?
Returns a synchronizable event (see Events) that is in a blocking state when tcp-accept on listener would block. If the event is chosen in a synchronization, the result is a list of two items, which correspond to the two results of tcp-accept. (If the event is not chosen, no connections are accepted.) The ports are placed into the management of the custodian that is the current custodian (see Custodians) at the time that tcp-accept-evt is called.

(tcp-abandon-port tcp-port)  void?
  tcp-port : tcp-port?
Like close-output-port or close-input-port (depending on whether tcp-port is an input or output port), but if tcp-port is an output port and its associated input port is not yet closed, then the other end of the TCP connection does not receive a TCP close message until the input port is also closed.

The TCP protocol does not include a “no longer reading” state on connections, so tcp-abandon-port is equivalent to close-input-port on input TCP ports.

(tcp-addresses tcp-port [port-numbers?])
  
(or/c (values string? string?)
      (values string? (integer-in 1 65535)
              string? (integer-in 1 65535)))
  tcp-port : (or/c tcp-port? tcp-listener?)
  port-numbers? : any/c = #f
Returns two strings when port-numbers? is #f (the default). The first string is the Internet address for the local machine a viewed by the given TCP port’s connection. (For most machines, the answer corresponds to the current machine’s only Internet address, but when a machine serves multiple addresses, the result is connection-specific.) The second string is the Internet address for the other end of the connection.

If port-numbers? is true, then four results are returned: a string for the local machine’s address, an exact integer between 1 and 65535 for the local machine’s port number, a string for the remote machine’s address, and an exact integer between 1 and 65535 for the remote machine’s port number.

If the given port has been closed, the exn:fail:network exception is raised.

(tcp-port? v)  boolean?
  v : any/c
Returns #t if v is a TCP port – which is a port returned by tcp-accept, tcp-connect, tcp-accept/enable-break, or tcp-connect/enable-break#f otherwise.