--- name: TCP sockets tutorial --- # TCP sockets A TCP socket carries a reliable, ordered byte stream between two processes that may be on different machines. This page builds the two halves of a TCP conversation from the raw built-ins: a **client** that connects and exchanges a line, and a **forking server** that accepts connections and handles each in its own child. The high-level convenience module `IO::Socket::INET` is not available in PetaPerl, so every recipe here uses the built-in [`socket`](../../p5/core/perlfunc/socket) layer directly with address helpers from the `Socket` module. That is no loss: the built-in form is what `IO::Socket::INET` wraps, and seeing it in the open makes the handshake legible. ## The address helpers A socket address is a packed C `struct sockaddr_in`. The `Socket` module builds and takes apart that structure for you: ```perl use Socket; my $packed = sockaddr_in($port, $ip); # build my ($port, $ip) = sockaddr_in($packed); # take apart ``` `$ip` is itself a packed four-byte address. `inet_aton` turns a dotted-quad string into one; `inet_ntoa` turns it back. The constant `INADDR_LOOPBACK` is the packed form of `127.0.0.1`, and `INADDR_ANY` means "every local interface". ```perl use Socket; my $ip = inet_aton("127.0.0.1"); print inet_ntoa($ip), "\n"; # 127.0.0.1 ``` ## A TCP client The client creates a socket, connects it to a server address, and then reads and writes the handle like any other stream. ```perl use Socket; my $host = "127.0.0.1"; my $port = 8080; socket(my $sock, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die "socket: $!"; my $addr = sockaddr_in($port, inet_aton($host)); connect($sock, $addr) or die "connect: $!"; $sock->autoflush(1); # send each line as it is printed print $sock "ping\n"; my $reply = <$sock>; print "server said: $reply"; # server said: pong: ping close $sock; ``` The one line that catches everyone is `$sock->autoflush(1)`. Without it, `print $sock "ping\n"` sits in Perl's output buffer, the server never sees it, and both sides block forever waiting on each other. On any socket where you write a request and then read a reply, set autoflush before the first write. ## A forking server A server binds to a port, listens, and then loops accepting connections. The classic structure handles each client in a forked child so one slow client cannot stall the next: ```perl use Socket; use POSIX qw(WNOHANG); # for the non-blocking reaper my $port = 8080; my $backlog = 128; # pending-connection queue depth socket(my $server, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die "socket: $!"; # Let the address be reused immediately after a restart. setsockopt($server, SOL_SOCKET, SO_REUSEADDR, 1) or die "setsockopt: $!"; bind($server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!"; listen($server, $backlog) or die "listen: $!"; # Reap finished children so they do not become zombies. $SIG{CHLD} = sub { 1 while waitpid(-1, WNOHANG) > 0 }; print "listening on port $port\n"; while (accept(my $client, $server)) { my $pid = fork(); die "fork: $!" unless defined $pid; if ($pid == 0) { # Child: serve this one connection, then exit. close $server; # child does not need the listener $client->autoflush(1); while (my $line = <$client>) { print $client "pong: $line"; } close $client; exit 0; } # Parent: hand the connection to the child and move on. close $client; # parent does not need this client } ``` Three details make this server correct rather than merely working: - **`SO_REUSEADDR` before `bind`.** After a server exits, the kernel keeps the port in `TIME_WAIT` for a while. Without this option a restart fails with "Address already in use". Set it and the restart binds immediately. - **The `$SIG{CHLD}` reaper.** Every forked child becomes a zombie when it exits until the parent calls [`waitpid`](../../p5/core/perlfunc/waitpid). The handler reaps all finished children non-blockingly with `WNOHANG`, so the accept loop never pauses to wait. - **Both sides close the descriptor they do not use.** The child closes the listening socket; the parent closes the accepted client socket. If either skips its `close`, the underlying file descriptor stays open in the wrong process and the connection never sees EOF. ## Running both halves together For a self-contained demonstration, fork the server into the background and run the client in the parent. The server binds to an ephemeral port (port `0`) and reports the port the kernel assigned: ```perl use Socket; # --- server child on an ephemeral port --- socket(my $server, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die "socket: $!"; setsockopt($server, SOL_SOCKET, SO_REUSEADDR, 1) or die "setsockopt: $!"; bind($server, sockaddr_in(0, INADDR_LOOPBACK)) or die "bind: $!"; listen($server, 128) or die "listen: $!"; my ($port) = sockaddr_in(getsockname($server)); my $kid = fork() // die "fork: $!"; if ($kid == 0) { accept(my $client, $server) or die "accept: $!"; $client->autoflush(1); my $line = <$client>; print $client "pong: $line"; close $client; exit 0; } # --- client in the parent --- socket(my $sock, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die; connect($sock, sockaddr_in($port, INADDR_LOOPBACK)) or die "connect: $!"; $sock->autoflush(1); print $sock "ping\n"; print "client got: ", scalar <$sock>; # client got: pong: ping close $sock; waitpid($kid, 0); ``` `getsockname($server)` reports the local address the socket is bound to. Unpacking it with `sockaddr_in` recovers the port the kernel chose, which the client then connects to - the standard way to write a test that does not hard-code a port. ## Reference cross-links Each call has a per-built-in reference page with the full argument shape and return value: - [`socket`](../../p5/core/perlfunc/socket) - create the endpoint - [`bind`](../../p5/core/perlfunc/bind) - attach it to a local address - [`listen`](../../p5/core/perlfunc/listen) - mark it as accepting connections - [`accept`](../../p5/core/perlfunc/accept) - take the next pending connection - [`connect`](../../p5/core/perlfunc/connect) - reach out to a server - [`setsockopt`](../../p5/core/perlfunc/setsockopt) - set `SO_REUSEADDR` and friends - [`getsockname`](../../p5/core/perlfunc/getsockname) - discover the bound port - [`fork`](../../p5/core/perlfunc/fork) and [`waitpid`](../../p5/core/perlfunc/waitpid) - spawn and reap the per-client child - [`%SIG`](../../p5/core/perlvar/signals) - the `CHLD` reaper handler ## Next For local-only stream sockets without the network stack, and for connectionless datagrams, see [UNIX-domain and UDP sockets](sockets-unix-udp).