--- name: UNIX-domain and UDP sockets tutorial --- # UNIX-domain and UDP sockets Not every socket reaches across a network. This page covers two lighter-weight relatives of the TCP socket from the [previous page](sockets-tcp): a **UNIX-domain socket pair** for two related processes on one machine, and a **UDP socket** for connectionless datagrams. Both use the same [`socket`](../../p5/core/perlfunc/socket) family of built-ins and the same `Socket` address helpers. The high-level `IO::Socket::*` wrappers are not available in PetaPerl, so the recipes stay at the built-in layer. ## A socket pair for parent and child [`socketpair`](../../p5/core/perlfunc/socketpair) creates two connected sockets in one call, with no addresses, no `bind`, and no `connect`. It is the ideal channel between a parent and a child it is about to fork: full-duplex (both ends can read and write), local, and already connected the moment it returns. ```perl use Socket; socketpair(my $child_end, my $parent_end, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; my $kid = fork() // die "fork: $!"; if ($kid == 0) { # Child keeps its end, closes the parent's. close $parent_end; $child_end->autoflush(1); print $child_end "child-says-hi\n"; my $back = <$child_end>; print "child got: $back"; # child got: ack exit 0; } # Parent keeps its end, closes the child's. close $child_end; $parent_end->autoflush(1); my $msg = <$parent_end>; print "parent got: $msg"; # parent got: child-says-hi print $parent_end "ack\n"; waitpid($kid, 0); ``` Why reach for `socketpair` over a plain [`pipe`](../../p5/core/perlfunc/pipe)? A pipe is one-directional - the reader reads, the writer writes, and that is fixed at creation. A socket pair is bidirectional: each end both reads and writes, so a request-and-reply exchange needs one `socketpair` call instead of two pipes wired in opposite directions. The autoflush rule from TCP applies unchanged: set it on each end before the first write, or a buffered request never reaches the other side and both processes block. ## A UDP datagram exchange UDP is connectionless. There is no `connect`, no `accept`, no stream - just discrete messages, each addressed to a destination and each preserving its own boundaries. A receiver binds to a port; a sender fires a datagram at it with [`send`](../../p5/core/perlfunc/send); the receiver collects it with [`recv`](../../p5/core/perlfunc/recv), which also reports who sent it. ```perl use Socket; # --- receiver on an ephemeral port --- socket(my $server, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!"; bind($server, sockaddr_in(0, INADDR_LOOPBACK)) or die "bind: $!"; my ($port) = sockaddr_in(getsockname($server)); my $kid = fork() // die "fork: $!"; if ($kid == 0) { # Sender fires one datagram at the receiver's port. socket(my $client, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die; my $to = sockaddr_in($port, INADDR_LOOPBACK); send($client, "hello-udp", 0, $to) or die "send: $!"; exit 0; } # recv fills $buf and returns the sender's packed address. my $from = recv($server, my $buf, 65535, 0); my ($sender_port, $sender_ip) = sockaddr_in($from); print "got '$buf' from ", inet_ntoa($sender_ip), "\n"; # got 'hello-udp' from 127.0.0.1 waitpid($kid, 0); ``` What UDP gives you and what it does not: - **Message boundaries are preserved.** One `send` is one `recv`. A `recv` returns exactly one datagram, never two concatenated and never half of one. The `65535` is the maximum length you are willing to accept; a shorter datagram returns its real length. - **There is no `connect` and no handshake.** The sender does not open a connection; it addresses each datagram with `send`'s fourth argument. `recv` reports the sender's address so a reply can go back the same way. - **Delivery is not guaranteed.** UDP datagrams can be dropped, duplicated, or reordered by the network. Over the loopback interface, as in this recipe, that effectively never happens; over a real network you must handle loss yourself if it matters. ## Reference cross-links - [`socketpair`](../../p5/core/perlfunc/socketpair) - two connected local sockets - [`socket`](../../p5/core/perlfunc/socket) - create a datagram or stream endpoint - [`bind`](../../p5/core/perlfunc/bind) - attach the receiver to a local port - [`send`](../../p5/core/perlfunc/send) - fire a datagram at an address - [`recv`](../../p5/core/perlfunc/recv) - collect a datagram and its sender - [`getsockname`](../../p5/core/perlfunc/getsockname) - discover the bound port ## Next For shared memory and semaphores - channels the kernel owns rather than streams between processes - see [System V IPC](sysv-ipc).