.TH gen_tcp 3erl "kernel 5.1.1" "Ericsson AB" "Erlang Module Definition" .SH NAME gen_tcp \- Interface to TCP/IP sockets. .SH DESCRIPTION .LP This module provides functions for communicating with sockets using the TCP/IP protocol\&. .LP The following code fragment is a simple example of a client connecting to a server at port 5678, transferring a binary, and closing the connection: .LP .nf client() -> SomeHostInNet = "localhost", % to make it runnable on one machine {ok, Sock} = gen_tcp:connect(SomeHostInNet, 5678, [binary, {packet, 0}]), ok = gen_tcp:send(Sock, "Some Data"), ok = gen_tcp:close(Sock). .fi .LP At the other end, a server is listening on port 5678, accepts the connection, and receives the binary: .LP .nf server() -> {ok, LSock} = gen_tcp:listen(5678, [binary, {packet, 0}, {active, false}]), {ok, Sock} = gen_tcp:accept(LSock), {ok, Bin} = do_recv(Sock, []), ok = gen_tcp:close(Sock), Bin. do_recv(Sock, Bs) -> case gen_tcp:recv(Sock, 0) of {ok, B} -> do_recv(Sock, [Bs, B]); {error, closed} -> {ok, list_to_binary(Bs)} end. .fi .LP For more examples, see section \fBExamples\fR\&\&. .SH DATA TYPES .nf \fBoption()\fR\& = .br {active, true | false | once | -32768\&.\&.32767} | .br {buffer, integer() >= 0} | .br {delay_send, boolean()} | .br {deliver, port | term} | .br {dontroute, boolean()} | .br {exit_on_close, boolean()} | .br {header, integer() >= 0} | .br {high_msgq_watermark, integer() >= 1} | .br {high_watermark, integer() >= 0} | .br {keepalive, boolean()} | .br {linger, {boolean(), integer() >= 0}} | .br {low_msgq_watermark, integer() >= 1} | .br {low_watermark, integer() >= 0} | .br {mode, list | binary} | .br list | .br binary | .br {nodelay, boolean()} | .br {packet, .br 0 | .br 1 | .br 2 | .br 4 | .br raw | .br sunrm | .br asn1 | .br cdr | .br fcgi | .br line | .br tpkt | .br http | .br httph | .br http_bin | .br httph_bin} | .br {packet_size, integer() >= 0} | .br {priority, integer() >= 0} | .br {raw, .br Protocol :: integer() >= 0, .br OptionNum :: integer() >= 0, .br ValueBin :: binary()} | .br {recbuf, integer() >= 0} | .br {reuseaddr, boolean()} | .br {send_timeout, integer() >= 0 | infinity} | .br {send_timeout_close, boolean()} | .br {show_econnreset, boolean()} | .br {sndbuf, integer() >= 0} | .br {tos, integer() >= 0} | .br {ipv6_v6only, boolean()} .br .fi .nf \fBoption_name()\fR\& = .br active | .br buffer | .br delay_send | .br deliver | .br dontroute | .br exit_on_close | .br header | .br high_msgq_watermark | .br high_watermark | .br keepalive | .br linger | .br low_msgq_watermark | .br low_watermark | .br mode | .br nodelay | .br packet | .br packet_size | .br priority | .br {raw, .br Protocol :: integer() >= 0, .br OptionNum :: integer() >= 0, .br ValueSpec :: .br (ValueSize :: integer() >= 0) | (ValueBin :: binary())} | .br recbuf | .br reuseaddr | .br send_timeout | .br send_timeout_close | .br show_econnreset | .br sndbuf | .br tos | .br ipv6_v6only .br .fi .nf \fBconnect_option()\fR\& = .br {ip, \fBinet:socket_address()\fR\&} | .br {fd, Fd :: integer() >= 0} | .br {ifaddr, \fBinet:socket_address()\fR\&} | .br \fBinet:address_family()\fR\& | .br {port, \fBinet:port_number()\fR\&} | .br {tcp_module, module()} | .br \fBoption()\fR\& .br .fi .nf \fBlisten_option()\fR\& = .br {ip, \fBinet:socket_address()\fR\&} | .br {fd, Fd :: integer() >= 0} | .br {ifaddr, \fBinet:socket_address()\fR\&} | .br \fBinet:address_family()\fR\& | .br {port, \fBinet:port_number()\fR\&} | .br {backlog, B :: integer() >= 0} | .br {tcp_module, module()} | .br \fBoption()\fR\& .br .fi .nf .B socket() .br .fi .RS .LP As returned by \fB\fIaccept/1,2\fR\&\fR\& and \fB\fIconnect/3,4\fR\&\fR\&\&. .RE .SH EXPORTS .LP .nf .B accept(ListenSocket) -> {ok, Socket} | {error, Reason} .br .fi .br .nf .B accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 ListenSocket = \fBsocket()\fR\& .br .RS 2 Returned by \fB\fIlisten/2\fR\&\fR\&\&. .RE Timeout = timeout() .br Socket = \fBsocket()\fR\& .br Reason = closed | timeout | system_limit | \fBinet:posix()\fR\& .br .RE .RE .RS .LP Accepts an incoming connection request on a listening socket\&. \fISocket\fR\& must be a socket returned from \fB\fIlisten/2\fR\&\fR\&\&. \fITimeout\fR\& specifies a time-out value in milliseconds\&. Defaults to \fIinfinity\fR\&\&. .LP Returns: .RS 2 .TP 2 * \fI{ok, Socket}\fR\& if a connection is established .LP .TP 2 * \fI{error, closed}\fR\& if \fIListenSocket\fR\& is closed .LP .TP 2 * \fI{error, timeout}\fR\& if no connection is established within the specified time .LP .TP 2 * \fI{error, system_limit}\fR\& if all available ports in the Erlang emulator are in use .LP .TP 2 * A POSIX error value if something else goes wrong, see \fB\fIinet(3erl)\fR\&\fR\& for possible error values .LP .RE .LP Packets can be sent to the returned socket \fISocket\fR\& using \fB\fIsend/2\fR\&\fR\&\&. Packets sent from the peer are delivered as messages (unless \fI{active, false}\fR\& is specified in the option list for the listening socket, in which case packets are retrieved by calling \fB\fIrecv/2\fR\&\fR\&): .LP .nf {tcp, Socket, Data} .fi .LP .RS -4 .B Note: .RE The \fIaccept\fR\& call does \fInot\fR\& have to be issued from the socket owner process\&. Using version 5\&.5\&.3 and higher of the emulator, multiple simultaneous accept calls can be issued from different processes, which allows for a pool of acceptor processes handling incoming connections\&. .RE .LP .nf .B close(Socket) -> ok .br .fi .br .RS .LP Types: .RS 3 Socket = \fBsocket()\fR\& .br .RE .RE .RS .LP Closes a TCP socket\&. .RE .LP .nf .B connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} .br .fi .br .nf .B connect(Address, Port, Options, Timeout) -> .B {ok, Socket} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Address = \fBinet:socket_address()\fR\& | \fBinet:hostname()\fR\& .br Port = \fBinet:port_number()\fR\& .br Options = [\fBconnect_option()\fR\&] .br Timeout = timeout() .br Socket = \fBsocket()\fR\& .br Reason = \fBinet:posix()\fR\& .br .RE .RE .RS .LP Connects to a server on TCP port \fIPort\fR\& on the host with IP address \fIAddress\fR\&\&. Argument \fIAddress\fR\& can be a hostname or an IP address\&. .LP The following options are available: .RS 2 .TP 2 .B \fI{ip, Address}\fR\&: If the host has many network interfaces, this option specifies which one to use\&. .TP 2 .B \fI{ifaddr, Address}\fR\&: Same as \fI{ip, Address}\fR\&\&. If the host has many network interfaces, this option specifies which one to use\&. .TP 2 .B \fI{fd, integer() >= 0}\fR\&: If a socket has somehow been connected without using \fIgen_tcp\fR\&, use this option to pass the file descriptor for it\&. If \fI{ip, Address}\fR\& and/or \fI{port, port_number()}\fR\& is combined with this option, the \fIfd\fR\& is bound to the specified interface and port before connecting\&. If these options are not specified, it is assumed that the \fIfd\fR\& is already bound appropriately\&. .TP 2 .B \fIinet\fR\&: Sets up the socket for IPv4\&. .TP 2 .B \fIinet6\fR\&: Sets up the socket for IPv6\&. .TP 2 .B \fIlocal\fR\&: Sets up a Unix Domain Socket\&. See \fB\fIinet:local_address()\fR\&\fR\& .TP 2 .B \fI{port, Port}\fR\&: Specifies which local port number to use\&. .TP 2 .B \fI{tcp_module, module()}\fR\&: Overrides which callback module is used\&. Defaults to \fIinet_tcp\fR\& for IPv4 and \fIinet6_tcp\fR\& for IPv6\&. .TP 2 .B \fIOpt\fR\&: See \fB\fIinet:setopts/2\fR\&\fR\&\&. .RE .LP Packets can be sent to the returned socket \fISocket\fR\& using \fB\fIsend/2\fR\&\fR\&\&. Packets sent from the peer are delivered as messages: .LP .nf {tcp, Socket, Data} .fi .LP If the socket is in \fI{active, N}\fR\& mode (see \fB\fIinet:setopts/2\fR\&\fR\& for details) and its message counter drops to \fI0\fR\&, the following message is delivered to indicate that the socket has transitioned to passive (\fI{active, false}\fR\&) mode: .LP .nf {tcp_passive, Socket} .fi .LP If the socket is closed, the following message is delivered: .LP .nf {tcp_closed, Socket} .fi .LP If an error occurs on the socket, the following message is delivered (unless \fI{active, false}\fR\& is specified in the option list for the socket, in which case packets are retrieved by calling \fB\fIrecv/2\fR\&\fR\&): .LP .nf {tcp_error, Socket, Reason} .fi .LP The optional \fITimeout\fR\& parameter specifies a time-out in milliseconds\&. Defaults to \fIinfinity\fR\&\&. .LP .RS -4 .B Note: .RE The default values for options specified to \fIconnect\fR\& can be affected by the Kernel configuration parameter \fIinet_default_connect_options\fR\&\&. For details, see \fB\fIinet(3erl)\fR\&\fR\&\&. .RE .LP .nf .B controlling_process(Socket, Pid) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = \fBsocket()\fR\& .br Pid = pid() .br Reason = closed | not_owner | badarg | \fBinet:posix()\fR\& .br .RE .RE .RS .LP Assigns a new controlling process \fIPid\fR\& to \fISocket\fR\&\&. The controlling process is the process that receives messages from the socket\&. If called by any other process than the current controlling process, \fI{error, not_owner}\fR\& is returned\&. If the process identified by \fIPid\fR\& is not an existing local pid, \fI{error, badarg}\fR\& is returned\&. \fI{error, badarg}\fR\& may also be returned in some cases when \fISocket\fR\& is closed during the execution of this function\&. .LP If the socket is set in active mode, this function will transfer any messages in the mailbox of the caller to the new controlling process\&. If any other process is interacting with the socket while the transfer is happening, the transfer may not work correctly and messages may remain in the caller\&'s mailbox\&. For instance changing the sockets active mode before the transfere is complete may cause this\&. .RE .LP .nf .B listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Port = \fBinet:port_number()\fR\& .br Options = [\fBlisten_option()\fR\&] .br ListenSocket = \fBsocket()\fR\& .br Reason = system_limit | \fBinet:posix()\fR\& .br .RE .RE .RS .LP Sets up a socket to listen on port \fIPort\fR\& on the local host\&. .LP If \fIPort == 0\fR\&, the underlying OS assigns an available port number, use \fB\fIinet:port/1\fR\&\fR\& to retrieve it\&. .LP The following options are available: .RS 2 .TP 2 .B \fIlist\fR\&: Received \fIPacket\fR\& is delivered as a list\&. .TP 2 .B \fIbinary\fR\&: Received \fIPacket\fR\& is delivered as a binary\&. .TP 2 .B \fI{backlog, B}\fR\&: \fIB\fR\& is an integer >= \fI0\fR\&\&. The backlog value defines the maximum length that the queue of pending connections can grow to\&. Defaults to \fI5\fR\&\&. .TP 2 .B \fI{ip, Address}\fR\&: If the host has many network interfaces, this option specifies which one to listen on\&. .TP 2 .B \fI{port, Port}\fR\&: Specifies which local port number to use\&. .TP 2 .B \fI{fd, Fd}\fR\&: If a socket has somehow been connected without using \fIgen_tcp\fR\&, use this option to pass the file descriptor for it\&. .TP 2 .B \fI{ifaddr, Address}\fR\&: Same as \fI{ip, Address}\fR\&\&. If the host has many network interfaces, this option specifies which one to use\&. .TP 2 .B \fIinet6\fR\&: Sets up the socket for IPv6\&. .TP 2 .B \fIinet\fR\&: Sets up the socket for IPv4\&. .TP 2 .B \fI{tcp_module, module()}\fR\&: Overrides which callback module is used\&. Defaults to \fIinet_tcp\fR\& for IPv4 and \fIinet6_tcp\fR\& for IPv6\&. .TP 2 .B \fIOpt\fR\&: See \fB\fIinet:setopts/2\fR\&\fR\&\&. .RE .LP The returned socket \fIListenSocket\fR\& can only be used in calls to \fB\fIaccept/1,2\fR\&\fR\&\&. .LP .RS -4 .B Note: .RE The default values for options specified to \fIlisten\fR\& can be affected by the Kernel configuration parameter \fIinet_default_listen_options\fR\&\&. For details, see \fB\fIinet(3erl)\fR\&\fR\&\&. .RE .LP .nf .B recv(Socket, Length) -> {ok, Packet} | {error, Reason} .br .fi .br .nf .B recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = \fBsocket()\fR\& .br Length = integer() >= 0 .br Timeout = timeout() .br Packet = string() | binary() | HttpPacket .br Reason = closed | \fBinet:posix()\fR\& .br HttpPacket = term() .br .RS 2 See the description of \fIHttpPacket\fR\& in \fB\fIerlang:decode_packet/3\fR\&\fR\& in ERTS\&. .RE .RE .RE .RS .LP Receives a packet from a socket in passive mode\&. A closed socket is indicated by return value \fI{error, closed}\fR\&\&. .LP Argument \fILength\fR\& is only meaningful when the socket is in \fIraw\fR\& mode and denotes the number of bytes to read\&. If \fILength\fR\& is \fI0\fR\&, all available bytes are returned\&. If \fILength\fR\& > \fI0\fR\&, exactly \fILength\fR\& bytes are returned, or an error; possibly discarding less than \fILength\fR\& bytes of data when the socket is closed from the other side\&. .LP The optional \fITimeout\fR\& parameter specifies a time-out in milliseconds\&. Defaults to \fIinfinity\fR\&\&. .RE .LP .nf .B send(Socket, Packet) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = \fBsocket()\fR\& .br Packet = iodata() .br Reason = closed | \fBinet:posix()\fR\& .br .RE .RE .RS .LP Sends a packet on a socket\&. .LP There is no \fIsend\fR\& call with a time-out option, use socket option \fIsend_timeout\fR\& if time-outs are desired\&. See section \fBExamples\fR\&\&. .RE .LP .nf .B shutdown(Socket, How) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = \fBsocket()\fR\& .br How = read | write | read_write .br Reason = \fBinet:posix()\fR\& .br .RE .RE .RS .LP Closes a socket in one or two directions\&. .LP \fIHow == write\fR\& means closing the socket for writing, reading from it is still possible\&. .LP If \fIHow == read\fR\& or there is no outgoing data buffered in the \fISocket\fR\& port, the socket is shut down immediately and any error encountered is returned in \fIReason\fR\&\&. .LP If there is data buffered in the socket port, the attempt to shutdown the socket is postponed until that data is written to the kernel socket send buffer\&. If any errors are encountered, the socket is closed and \fI{error, closed}\fR\& is returned on the next \fB\fIrecv/2\fR\&\fR\& or \fB\fIsend/2\fR\&\fR\&\&. .LP Option \fI{exit_on_close, false}\fR\& is useful if the peer has done a shutdown on the write side\&. .RE .SH "EXAMPLES" .LP The following example illustrates use of option \fI{active,once}\fR\& and multiple accepts by implementing a server as a number of worker processes doing accept on a single listening socket\&. Function \fIstart/2\fR\& takes the number of worker processes and the port number on which to listen for incoming connections\&. If \fILPort\fR\& is specified as \fI0\fR\&, an ephemeral port number is used, which is why the start function returns the actual port number allocated: .LP .nf start(Num,LPort) -> case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of {ok, ListenSock} -> start_servers(Num,ListenSock), {ok, Port} = inet:port(ListenSock), Port; {error,Reason} -> {error,Reason} end. start_servers(0,_) -> ok; start_servers(Num,LS) -> spawn(?MODULE,server,[LS]), start_servers(Num-1,LS). server(LS) -> case gen_tcp:accept(LS) of {ok,S} -> loop(S), server(LS); Other -> io:format("accept returned ~w - goodbye!~n",[Other]), ok end. loop(S) -> inet:setopts(S,[{active,once}]), receive {tcp,S,Data} -> Answer = process(Data), % Not implemented in this example gen_tcp:send(S,Answer), loop(S); {tcp_closed,S} -> io:format("Socket ~w closed [~w]~n",[S,self()]), ok end. .fi .LP Example of a simple client: .LP .nf client(PortNo,Message) -> {ok,Sock} = gen_tcp:connect("localhost",PortNo,[{active,false}, {packet,2}]), gen_tcp:send(Sock,Message), A = gen_tcp:recv(Sock,0), gen_tcp:close(Sock), A. .fi .LP The \fIsend\fR\& call does not accept a time-out option because time-outs on send is handled through socket option \fIsend_timeout\fR\&\&. The behavior of a send operation with no receiver is mainly defined by the underlying TCP stack and the network infrastructure\&. To write code that handles a hanging receiver that can eventually cause the sender to hang on a \fIsend\fR\& do like the following\&. .LP Consider a process that receives data from a client process to be forwarded to a server on the network\&. The process is connected to the server through TCP/IP and does not get any acknowledge for each message it sends, but has to rely on the send time-out option to detect that the other end is unresponsive\&. Option \fIsend_timeout\fR\& can be used when connecting: .LP .nf \&... {ok,Sock} = gen_tcp:connect(HostAddress, Port, [{active,false}, {send_timeout, 5000}, {packet,2}]), loop(Sock), % See below \&... .fi .LP In the loop where requests are handled, send time-outs can now be detected: .LP .nf loop(Sock) -> receive {Client, send_data, Binary} -> case gen_tcp:send(Sock,[Binary]) of {error, timeout} -> io:format("Send timeout, closing!~n", []), handle_send_timeout(), % Not implemented here Client ! {self(),{error_sending, timeout}}, %% Usually, it's a good idea to give up in case of a %% send timeout, as you never know how much actually %% reached the server, maybe only a packet header?! gen_tcp:close(Sock); {error, OtherSendError} -> io:format("Some other error on socket (~p), closing", [OtherSendError]), Client ! {self(),{error_sending, OtherSendError}}, gen_tcp:close(Sock); ok -> Client ! {self(), data_sent}, loop(Sock) end end. .fi .LP Usually it suffices to detect time-outs on receive, as most protocols include some sort of acknowledgment from the server, but if the protocol is strictly one way, option \fIsend_timeout\fR\& comes in handy\&.