Skip to content

Instantly share code, notes, and snippets.

@alekxeyuk
Created August 19, 2025 09:50
Show Gist options
  • Select an option

  • Save alekxeyuk/638981262345dd8d595a65a253ae6ed6 to your computer and use it in GitHub Desktop.

Select an option

Save alekxeyuk/638981262345dd8d595a65a253ae6ed6 to your computer and use it in GitHub Desktop.

Below is a step‑by‑step, ordered list of the POSIX functions you normally call when you work with a Unix‑domain (AF_LOCAL / AF_UNIX) stream socket (SOCK_STREAM).
I split the list into two sections – one for the server side and one for the client side – because the order of calls differs slightly.


1️⃣ Server side (creates a listening socket)

# Function (header) What it does Typical usage notes
1 socket(int domain, int type, int protocol)
#include <sys/socket.h>
Creates a new socket descriptor. domain = AF_LOCAL (or AF_UNIX), type = SOCK_STREAM, protocol = 0.
2 unlink(const char *pathname)
#include <unistd.h>
Removes a stale socket‑file name if it already exists. Do this before bind() so bind() won’t fail with EADDRINUSE.
3 bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
#include <sys/socket.h>
Associates the socket with a pathname in the filesystem. addr points to a struct sockaddr_un whose sun_path holds the file name.
4 listen(int sockfd, int backlog)
#include <sys/socket.h>
Marks the socket as a passive (listening) socket. backlog is the maximum number of pending connections (e.g., 5‑10).
5 accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
#include <sys/socket.h>
Blocks (or returns immediately if non‑blocking) until a client connects, returning a new connected socket descriptor. Use the returned descriptor for all I/O with that client.
6 (optional) getsockname(), getpeername() Retrieve local or peer address info (mostly for debugging).
7 read() / recv()
#include <unistd.h> / <sys/socket.h>
Receive data from the connected client. For stream sockets you can treat them as regular file descriptors.
8 write() / send() Send data to the client.
9 (optional) shutdown(int sockfd, int how)
#include <sys/socket.h>
Gracefully close one or both directions of the connection (SHUT_RD, SHUT_WR, SHUT_RDWR).
10 close(int fd)
#include <unistd.h>
Release the socket descriptor.
11 unlink(const char *pathname) (again) Remove the socket file from the filesystem when the server terminates.

Typical server flow (pseudo‑code)

int listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
unlink(&quot;/tmp/my_socket&quot;);                     // step 2
struct sockaddr_un addr = {0};
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, &quot;/tmp/my_socket&quot;);
bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)); // step 3
listen(listen_fd, 10);                         // step 4

while (1) {
    int conn_fd = accept(listen_fd, NULL, NULL); // step 5
    // … read/write on conn_fd …
    close(conn_fd);                            // step 10
}
close(listen_fd);
unlink(&quot;/tmp/my_socket&quot;);                      // step 11

2️⃣ Client side (connects to the server)

# Function (header) What it does Typical usage notes
1 socket(int domain, int type, int protocol) Creates a new socket descriptor. Same arguments as the server.
2 connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) Initiates a connection to the server’s socket file. addr is a struct sockaddr_un with the same pathname the server bound to.
3 write() / send() Send request/data to the server.
4 read() / recv() Receive response/data from the server.
5 (optional) shutdown(int sockfd, int how) Gracefully close one or both directions.
6 close(int fd) Release the socket descriptor.

Typical client flow (pseudo‑code)

int sock = socket(AF_LOCAL, SOCK_STREAM, 0);   // step 1
struct sockaddr_un addr = {0};
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, &quot;/tmp/my_socket&quot;);
connect(sock, (struct sockaddr *)&addr, sizeof(addr)); // step 2

write(sock, &quot;Hello&quot;, 5);                       // step 3
char buf[256];
int n = read(sock, buf, sizeof(buf));         // step 4
/* … process … */

close(sock);                                   // step 6

3️⃣ “Extra” helper functions you often see together with AF_LOCAL / SOCK_STREAM

Function Header Why it’s useful in this context
fcntl() <fcntl.h> Set the socket non‑blocking (O_NONBLOCK) before accept()/connect().
setsockopt() <sys/socket.h> Tune options like SO_REUSEADDR (rarely needed for AF_LOCAL) or SO_RCVBUF / SO_SNDBUF.
getsockopt() <sys/socket.h> Query current socket options.
select() / poll() / epoll() <sys/select.h>, <poll.h>, <sys/epoll.h> Multiplex I/O when handling many client connections.
socketpair() <sys/socket.h> Quickly create a pair of connected AF_LOCAL stream sockets (useful for intra‑process communication).
chmod() / chown() <sys/stat.h> Adjust permissions of the socket file after bind() if you need restricted access.
unlinkat() <fcntl.h> Same as unlink() but works with a directory file descriptor (useful in sandboxed environments).

TL;DR – One‑liner cheat sheet

Server: socket → unlink (old) → bind → listen → accept → (read/write) → close → unlink (final)

Client: socket → connect → (write/read) → close

Feel free to ask if you need a concrete C example, a Python wrapper, or details on error handling for any of these calls!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment