0% found this document useful (0 votes)
151 views23 pages

Network Programming-Module 04

This document covers advanced I/O functions in network programming, focusing on socket timeouts, various send/receive functions, and Unix domain protocols. It details the purpose and usage of functions like readv, writev, sendfile, and mmap, as well as the importance of setting socket timeouts to prevent indefinite blocking. Additionally, it explains Unix domain sockets, their characteristics, and how to implement them in C.

Uploaded by

Minhaj Choudhry
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
151 views23 pages

Network Programming-Module 04

This document covers advanced I/O functions in network programming, focusing on socket timeouts, various send/receive functions, and Unix domain protocols. It details the purpose and usage of functions like readv, writev, sendfile, and mmap, as well as the importance of setting socket timeouts to prevent indefinite blocking. Additionally, it explains Unix domain sockets, their characteristics, and how to implement them in C.

Uploaded by

Minhaj Choudhry
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Network Programming(MSCS203)

Module-4
Advanced I/O functions – Socket timeouts, recv and send functions, readv, writev, sendmsg and
recvmsg. Unix domain protocols - socket address structure, socketpair functions, socket functions
Unix domain stream client/server , Unix domain Datagram client/server .

✅ What Are Advanced I/O Functions?


These are system calls and library functions designed to handle:
 Non-blocking or asynchronous I/O
 Scatter/gather I/O
 File descriptor passing
 Vectorized I/O
 Memory-mapped files
 Efficient data transfers
They go beyond basic file/socket I/O and are often used in servers, databases, operating systems, and
high-performance apps.

🧰 List of Common Advanced I/O Functions


Function Purpose
readv() / writev() Scatter/gather I/O
sendfile() Kernel-space file transfer
splice() / tee() / vmsplice() Zero-copy I/O
mmap() Memory-mapped file I/O
aio_read() / aio_write() POSIX asynchronous I/O
recvmsg() / sendmsg() Advanced message passing
select() / poll() / epoll() / pselect() I/O multiplexing
fcntl() Set non-blocking mode
dup() / dup2() / dup3() Duplicate file descriptors
io_uring (Linux) High-performance async I/O API

🔍 1. readv() / writev() – Vector I/O (Scatter/Gather)


These functions allow reading/writing from multiple buffers in one system call.
Syntax:
c
CopyEdit
#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);


ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
Example:
c
CopyEdit
struct iovec iov[2];
char buf1[10], buf2[20];
iov[0].iov_base = buf1;
iov[0].iov_len = sizeof(buf1);
iov[1].iov_base = buf2;
iov[1].iov_len = sizeof(buf2);

readv(fd, iov, 2); // Reads into both buffers


✅ Efficient for sending structured data like headers + payload.

🔍 2. sendfile() – Zero-Copy File Transfer


Transfers data between a file descriptor and a socket without copying data into user space.
Syntax:
c
CopyEdit
#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);


✅ Used in web servers for high-speed file delivery.

🔍 3. mmap() – Memory-Mapped File I/O


Maps a file into the process's address space for random access via memory.
Syntax:
c
CopyEdit
#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
Example:
c
CopyEdit
char *data = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
printf("File begins with: %.10s\n", data);
✅ Fast for large file access; used in DB engines, compilers.

🔍 4. splice(), tee(), vmsplice() – Pipe-Based Zero-Copy I/O (Linux)


Transfer data between:
 file <-> pipe (splice())
 pipe <-> pipe (tee())
 memory <-> pipe (vmsplice())
These avoid user-space copying.
✅ Used in high-performance streaming servers.

🔍 5. POSIX AIO – aio_read(), aio_write() (Asynchronous I/O)


Asynchronous reads/writes that notify via signal or callback when complete.
Example:
c
CopyEdit
#include <aio.h>
struct aiocb cb;
cb.aio_fildes = fd;
cb.aio_buf = buffer;
cb.aio_nbytes = 1024;
cb.aio_offset = 0;

aio_read(&cb); // Doesn't block


✅ Useful in real-time systems and background I/O tasks.

🔍 6. recvmsg() / sendmsg() – Structured Network I/O


Used for:
 Sending/receiving multiple buffers
 Ancillary data (file descriptors, credentials, etc.)
 Datagram control
✅ Essential for UNIX domain sockets, SCM_RIGHTS (file descriptor passing).

🔍 7. io_uring – Modern Async I/O (Linux ≥ 5.1)


A new high-performance interface for asynchronous I/O, faster than epoll, aio, or select.
✅ Used by modern Linux servers (like Nginx, PostgreSQL) for massive performance.

🧰 Summary Table
Function Use Case Benefit
readv / writev Multi-buffer I/O Fewer syscalls
sendfile File → Socket Zero-copy
mmap File I/O via memory Random access, performance
splice / tee Pipe/file zero-copy No user-space copy
aio_read Async file I/O Background operations
recvmsg Advanced socket msg Control + data
io_uring Modern async I/O Extremely fast

✅ When to Use These?


Scenario Use
High-speed file serving sendfile, mmap
Structured message passing recvmsg, sendmsg
Scalable network server epoll, io_uring
Writing to multiple buffers writev
Reading multiple buffers readv
Async reads in GUI/RT app aio_read

✅ What Are Socket Timeouts?


A socket timeout is a limit on how long a socket operation can block (wait) before giving up. If the
operation (like read(), recv(), or connect()) doesn’t complete within the specified time, the call fails with
a timeout error (EAGAIN or EWOULDBLOCK for non-blocking I/O).

🧰 Why Use Socket Timeouts?


Socket timeouts are essential for:
 Preventing indefinite blocking
 Avoiding deadlocks or hanging apps
 Building responsive client/server systems
 Handling slow or broken network connections gracefully

🔧 Types of Socket Timeouts


Type Applies to Function
Read timeout recv(), read() How long to wait for incoming data
Write timeout send(), write() How long to wait for the send buffer to be free
Connect timeout connect() Time to wait for establishing connection

✅ Setting Socket Timeouts in C (POSIX)


Use the setsockopt() function with options SO_RCVTIMEO (recv) and SO_SNDTIMEO (send).
🔹 Example – Set Read Timeout:
c
CopyEdit
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>

struct timeval timeout;


timeout.tv_sec = 5; // 5 seconds timeout
timeout.tv_usec = 0;

setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));


🔹 Example – Set Write Timeout:
c
CopyEdit
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
🔁 Notes:
 These apply only to blocking sockets.
 If the timeout expires, recv() or send() will return -1, and errno will be set to EAGAIN or
EWOULDBLOCK.

🔍 Set Connect Timeout


For TCP, connect() can block for a long time. To set a timeout:
🔸 Method: Use Non-blocking Connect + select() or poll()
c
CopyEdit
fcntl(sockfd, F_SETFL, O_NONBLOCK);
connect(sockfd, ...);

fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sockfd, &fdset);
struct timeval tv = {5, 0}; // 5 sec timeout

if (select(sockfd + 1, NULL, &fdset, NULL, &tv) > 0) {


// Check SO_ERROR with getsockopt to confirm connection success
}

🧰 How to Check Timeout Behavior


If a timeout occurs:
 recv() / read() / accept() returns -1
 errno will be:
o EAGAIN or EWOULDBLOCK (if timeout)
o ETIMEDOUT (for connect() timeout)

✅ Socket Timeouts in Other Languages


Python (socket module)
python
CopyEdit
import socket

s = socket.socket()
s.settimeout(5) # Applies to connect, recv, send
Java
java
CopyEdit
socket.setSoTimeout(5000); // 5 seconds read timeout

🔁 Summary Table
Operation Timeout Option Purpose
recv() / read() SO_RCVTIMEO Read timeout
send() / write() SO_SNDTIMEO Write timeout
connect() Non-blocking + select() Connection timeout

🧰 Example Use Case


Imagine a TCP client trying to connect to a server:
 You don’t want it to hang forever if the server is unreachable.
 Use a connect timeout to fail after 5 seconds.
 Use a read timeout to avoid waiting endlessly for server replies.
recv and send functions, readv, writev, sendmsg and recvmsg:

Let's explain each of the following functions in detail — including how they work, their parameters, and
when you should use them:
1. recv()
2. send()
3. readv()
4. writev()
5. recvmsg()
6. sendmsg()

✅ 1. recv() – Receive Data from a Socket


🔹 Purpose:
Receives data from a connected socket (TCP) or datagram socket (UDP).
🔧 Syntax:
c
CopyEdit
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
🔸 Parameters:
Parameter Description
sockfd Socket file descriptor
buf Buffer to store received data
len Maximum number of bytes to read
flags Options like MSG_PEEK, MSG_WAITALL
🔸 Common Flags:
 0: Default (blocking)
 MSG_PEEK: Peek without removing data from buffer
 MSG_DONTWAIT: Non-blocking
 MSG_WAITALL: Wait for full amount unless error
🧰 Example:
c
CopyEdit
char buffer[1024];
int n = recv(sockfd, buffer, sizeof(buffer), 0);
✅ Use When:
 You need to receive plain data over TCP/UDP
 Basic communication with minimal overhead

✅ 2. send() – Send Data Over a Socket


🔹 Purpose:
Sends data through a socket to a connected peer (TCP or connected UDP).
🔧 Syntax:
c
CopyEdit
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
🔸 Parameters:
Parameter Description
sockfd Socket file descriptor
buf Data to send
len Number of bytes to send
flags Same as recv() (e.g., MSG_DONTWAIT)
🧰 Example:
c
CopyEdit
const char *msg = "Hello!";
send(sockfd, msg, strlen(msg), 0);
✅ Use When:
 Sending normal TCP data or a UDP datagram (with connect())

✅ 3. readv() – Scatter Input to Multiple Buffers


🔹 Purpose:
Reads data into multiple non-contiguous memory buffers in a single syscall.
🔧 Syntax:
c
CopyEdit
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
🔧 struct iovec:
c
CopyEdit
struct iovec {
void *iov_base; // Starting address of buffer
size_t iov_len; // Number of bytes to read
};
🧰 Example:
c
CopyEdit
char header[128], body[512];
struct iovec iov[2];

iov[0].iov_base = header;
iov[0].iov_len = sizeof(header);
iov[1].iov_base = body;
iov[1].iov_len = sizeof(body);

readv(sockfd, iov, 2);


✅ Use When:
 You want to split incoming data into parts (like headers and body)
 Efficient server I/O handling with fewer syscalls

✅ 4. writev() – Gather Output from Multiple Buffers


🔹 Purpose:
Writes data from multiple buffers to a file descriptor in a single syscall.
🔧 Syntax:
c
CopyEdit
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
🧰 Example:
c
CopyEdit
const char *header = "HTTP/1.1 200 OK\n\n";
const char *body = "Hello, world!";
struct iovec iov[2];

iov[0].iov_base = (void *)header;


iov[0].iov_len = strlen(header);
iov[1].iov_base = (void *)body;
iov[1].iov_len = strlen(body);

writev(sockfd, iov, 2);


✅ Use When:
 Writing combined structured output (e.g., protocol headers + payload)
 Sending file + metadata efficiently

✅ 5. recvmsg() – Receive Structured Data and Control Info


🔹 Purpose:
Receives multiple buffers, address info, and ancillary (control) data (e.g., file descriptors, credentials).
🔧 Syntax:
c
CopyEdit
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
🔧 struct msghdr:
c
CopyEdit
struct msghdr {
void *msg_name; // Source address (for UDP)
socklen_t msg_namelen; // Length of address
struct iovec *msg_iov; // Array of buffers
int msg_iovlen; // Number of buffers
void *msg_control; // Ancillary data
size_t msg_controllen; // Size of control buffer
int msg_flags; // Flags returned
};
🧰 Example:
c
CopyEdit
char buffer[1024];
struct iovec iov = { buffer, sizeof(buffer) };
struct msghdr msg = {0};

msg.msg_iov = &iov;
msg.msg_iovlen = 1;

recvmsg(sockfd, &msg, 0);


✅ Use When:
 Receiving UDP from unknown sources
 Handling control messages, e.g., file descriptor passing via UNIX domain sockets
 Reading both data and metadata (e.g., timestamps, credentials)

✅ 6. sendmsg() – Send Structured Data and Control Info


🔹 Purpose:
Sends multi-buffer messages along with optional control data.
🔧 Syntax:
c
CopyEdit
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
🧰 Example:
c
CopyEdit
const char *msgText = "Hello";
struct iovec iov = { (void *)msgText, strlen(msgText) };
struct msghdr msg = {0};

msg.msg_iov = &iov;
msg.msg_iovlen = 1;

sendmsg(sockfd, &msg, 0);


✅ Use When:
 Sending file descriptors or credentials via SCM_RIGHTS
 Building structured protocol packets
 UDP: Sending to specific addresses

🧰 Summary Comparison Table


Function Buffers Control Info Address Info Use Case
recv() 1 ❌ ❌ Basic socket input
send() 1 ❌ ❌ Basic socket output
readv() Many ❌ ❌ Efficient scatter read
writev() Many ❌ ❌ Efficient gather write
recvmsg() Many ✅ ✅ (UDP) Advanced UDP/UNIX sockets
sendmsg() Many ✅ ✅ (UDP) Advanced UDP/UNIX sockets

✅ Real-World Examples
Use Case Function
Sending header + body in one shot writev()
Receiving UDP datagrams + source IP recvmsg()
Passing file descriptor to another process sendmsg()
Simple TCP message exchange send() / recv()
High-speed logging server writev()

Unix domain protocols:


What Are Unix Domain Sockets?
Unix domain sockets (UDS) are a form of inter-process communication (IPC) that allows processes on
the same host to communicate efficiently using the socket API.
Unlike Internet domain sockets (AF_INET), which use IP addresses and ports, Unix domain sockets use
file system paths as addresses.

✅ Key Characteristics
Feature Details
Addressing Uses file system paths (e.g. /tmp/mysock)
Domain AF_UNIX or AF_LOCAL
Transport types SOCK_STREAM (like TCP), SOCK_DGRAM (like UDP), SOCK_SEQPACKET
Scope Local only (same system)
Performance Faster than TCP/IP sockets (no networking stack)
Security Controlled by file system permissions
Special features Can pass file descriptors (via sendmsg() and recvmsg())

🧰 Types of Unix Domain Sockets


Type Description Comparable To
SOCK_STREAM Reliable, byte-oriented stream Like TCP
SOCK_DGRAM Message-oriented, unreliable Like UDP
SOCK_SEQPACKET Reliable, message-oriented Like a mix of TCP + UDP

🔧 How to Use Unix Domain Sockets (C)


1. Create a socket:
c
CopyEdit
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2. Define address:
c
CopyEdit
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/mysock");
3. Bind (server only):
c
CopyEdit
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
4. Connect (client):
c
CopyEdit
connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));

🧰 Example: Unix Domain Socket Echo Server (SOCK_STREAM)


🔹 Server:
c
CopyEdit
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/mysock");

unlink("/tmp/mysock"); // Remove existing socket file


bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 5);

int client_fd = accept(server_fd, NULL, NULL);


char buffer[1024];
int n = read(client_fd, buffer, sizeof(buffer));
write(client_fd, buffer, n); // Echo back
🔹 Client:
c
CopyEdit
int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/mysock");

connect(client_fd, (struct sockaddr*)&addr, sizeof(addr));


write(client_fd, "Hello", 5);

🧰 File Descriptor Passing (Advanced Feature)


Unix domain sockets can send file descriptors between processes using sendmsg() and recvmsg().
🧰 Example:
 Server creates a file (open()) and sends the file descriptor over the socket.
 Client receives the FD and reads the file, even though it didn’t open it.
✅ This enables powerful things like privilege separation and process isolation.

📌 Abstract Namespace (Linux-only)


In Linux, if the first byte of sun_path is \0, it creates an abstract namespace socket (does not exist in the
filesystem).
c
CopyEdit
addr.sun_path[0] = '\0';
strcpy(addr.sun_path + 1, "abstract_name");
✅ Useful for temporary or secure sockets.

✅ Advantages of Unix Domain Sockets


 Fast (no networking overhead)
 Secure (use filesystem permissions)
 Reliable (especially SOCK_STREAM)
 Can pass file descriptors, credentials
 No need for port numbers or IPs

❌ Limitations
 Only works on the same machine
 Path length limits (usually ~108 bytes for sun_path)
 Cannot use with standard internet protocols

🧰 Summary Table
Feature Unix Domain Socket TCP/IP Socket
Domain AF_UNIX AF_INET
Address Filesystem path IP:Port
Inter-host? ❌ Local only ✅ Yes
Speed 🚀 Very fast Slower
Use cases IPC on same system Network apps
Security Filesystem perms Firewall, SSL
Descriptor passing ✅ Yes ❌ No

✅ Real-World Use Cases


 X11, Docker, systemd — communicate via UDS
 Nginx → PHP-FPM or HAProxy → backend app via /run/app.sock
 Databases (e.g., PostgreSQL) use UDS for local client communication
 Microservices on same host use UDS for high-speed IPC

socket address structure:

The socket address structure is a key component in socket programming. It is used to define the address
of the socket — specifying where to connect, where to bind, or where to send/receive data.
Different socket domains (like AF_INET, AF_INET6, AF_UNIX) use different address structures. Let's
cover the most commonly used ones.

✅ 1. struct sockaddr
This is the generic socket address structure used for all socket types. Most socket functions like
connect(), bind(), accept(), and sendto() expect a pointer to this.
c
CopyEdit
struct sockaddr {
sa_family_t sa_family; // Address family (e.g., AF_INET)
char sa_data[14]; // Address data (depends on type)
};
You rarely use this directly — instead, you cast more specific structures to (struct sockaddr *).

✅ 2. struct sockaddr_in – IPv4 Address


Used for AF_INET (IPv4) sockets.
c
CopyEdit
#include <netinet/in.h>

struct sockaddr_in {
sa_family_t sin_family; // Address family: AF_INET
in_port_t sin_port; // Port number (network byte order)
struct in_addr sin_addr; // IP address
char sin_zero[8]; // Padding (unused)
};
🔧 struct in_addr:
c
CopyEdit
struct in_addr {
uint32_t s_addr; // IP address in network byte order
};
🧰 Example:
c
CopyEdit
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080); // Convert port to network byte order
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // Convert IP string to binary

✅ 3. struct sockaddr_in6 – IPv6 Address


Used for AF_INET6 sockets.
c
CopyEdit
#include <netinet/in.h>

struct sockaddr_in6 {
sa_family_t sin6_family; // AF_INET6
in_port_t sin6_port; // Port number
uint32_t sin6_flowinfo; // Flow information
struct in6_addr sin6_addr; // IPv6 address
uint32_t sin6_scope_id; // Scope ID (for link-local)
};

✅ 4. struct sockaddr_un – UNIX Domain Socket Address


Used with AF_UNIX or AF_LOCAL.
c
CopyEdit
#include <sys/un.h>

struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[108]; // Filesystem path to socket file
};
🧰 Example:
c
CopyEdit
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/mysocket");

🧰 Summary Table
Structure Used With Description
sockaddr All domains Generic wrapper
sockaddr_in AF_INET IPv4 address
sockaddr_in6 AF_INET6 IPv6 address
sockaddr_un AF_UNIX Filesystem-based IPC

🧰 Common Socket Functions and sockaddr


Function What it needs
bind() Address to bind socket to
connect() Address to connect to
sendto() Destination address for sending
recvfrom() Source address for receiving
accept() Populates peer’s address
All of these use (struct sockaddr *) with appropriate casting:
c
CopyEdit
(struct sockaddr *)&addr

socketpair functions:

🧰 What is socketpair()?
The socketpair() system call creates a pair of connected sockets that can be used for bidirectional
communication between two processes or threads — like a full-duplex pipe.
Think of it as creating two ends of a private communication channel.
✅ Syntax
c
CopyEdit
#include <sys/types.h>
#include <sys/socket.h>

int socketpair(int domain, int type, int protocol, int sv[2]);


🔹 Parameters:
Parameter Description
domain Address family (usually AF_UNIX or AF_LOCAL)
type Socket type (SOCK_STREAM or SOCK_DGRAM)
protocol Usually 0 (default for the given domain)
sv[2] Array to hold the two connected socket descriptors
🔙 Return:
 0 on success
 -1 on error (with errno set appropriately)

🧰 Example – Basic socketpair() Usage


c
CopyEdit
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>

int main() {
int sv[2]; // Socket pair

if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {


perror("socketpair");
return 1;
}

write(sv[0], "Hello", 5); // Send from sv[0]

char buf[10] = {0};


read(sv[1], buf, sizeof(buf)); // Receive at sv[1]

printf("Received: %s\n", buf);


return 0;
}

📌 Typical Use Cases


Use Case Description
Parent-child IPC After fork(), each process can use one end
Use Case Description
Multithreaded communication For threads needing simple bidirectional data sharing
Subprocess control Pass data to/from a subprocess (like shell or Python interpreter)
Emulating pipes More flexible than traditional pipe() (full-duplex)

🔄 Comparison: socketpair() vs pipe()


Feature socketpair() pipe()
Bidirectional ✅ Yes ❌ No (unidirectional)
File descriptors 2 (connected sockets) 2 (read/write ends)
Socket options ✅ Can use setsockopt() ❌ No options
Usable with select() ✅ Yes ✅ Yes
Domain support AF_UNIX only N/A

👶 Parent–Child Communication Example


c
CopyEdit
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>

int main() {
int sv[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

pid_t pid = fork();

if (pid == 0) { // Child
close(sv[0]); // Close parent end
write(sv[1], "Child", 5);
} else { // Parent
close(sv[1]); // Close child end
char buf[10] = {0};
read(sv[0], buf, sizeof(buf));
printf("Parent received: %s\n", buf);
}

return 0;
}

🔧 Advanced Use – sendmsg() with File Descriptor Passing


Because socketpair() creates AF_UNIX sockets, you can use them to:
 Pass file descriptors (SCM_RIGHTS)
 Pass credentials (SCM_CREDENTIALS)
 Send ancillary data (like rights or control messages)
✅ This is used in privilege separation, sandboxing, and modular application designs.
🔒 Security and Permissions
 No network involvement — secure and local
 File descriptors can’t be intercepted like TCP/IP traffic
 You can set read/write permissions and buffer sizes using fcntl() and setsockopt()

✅ Summary
Feature socketpair()
Domain Usually AF_UNIX
Type SOCK_STREAM or SOCK_DGRAM
Bidirectional? ✅ Yes
Works after fork()? ✅ Yes
File descriptor passing ✅ Yes (via sendmsg()/recvmsg())
Ideal for Local IPC, thread/process comm

🧰 What Are Unix Domain Stream Sockets?


 Use AF_UNIX (or AF_LOCAL) and SOCK_STREAM
 Create full-duplex, reliable communication (like TCP)
 Use file paths instead of IP/port for addressing
 Ideal for local client-server IPC

✅ Key Functions (Client + Server)


Function Purpose
socket() Create the socket
bind() Server binds socket to path
listen() Server starts listening
accept() Server accepts client connections
connect() Client connects to server
read()/write() or recv()/send() Send/receive data
close() Close socket file descriptors
unlink() Remove socket file (server)

🔧 Server Code – Unix Domain Stream Socket


c
CopyEdit
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define SOCKET_PATH "/tmp/unix_stream.sock"


int main() {
int server_fd, client_fd;
struct sockaddr_un addr;
char buf[100];

server_fd = socket(AF_UNIX, SOCK_STREAM, 0);


if (server_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}

unlink(SOCKET_PATH); // Remove previous socket file

memset(&addr, 0, sizeof(struct sockaddr_un));


addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);

if (bind(server_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {


perror("bind");
exit(EXIT_FAILURE);
}

listen(server_fd, 5);
printf("Server listening at %s\n", SOCKET_PATH);

client_fd = accept(server_fd, NULL, NULL);


if (client_fd < 0) {
perror("accept");
exit(EXIT_FAILURE);
}

int n = read(client_fd, buf, sizeof(buf));


buf[n] = '\0';
printf("Server received: %s\n", buf);

write(client_fd, "ACK from server", 15);

close(client_fd);
close(server_fd);
unlink(SOCKET_PATH);
return 0;
}

🧰 Client Code – Unix Domain Stream Socket


c
CopyEdit
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define SOCKET_PATH "/tmp/unix_stream.sock"

int main() {
int sockfd;
struct sockaddr_un addr;
char buf[100];

sockfd = socket(AF_UNIX, SOCK_STREAM, 0);


if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}

memset(&addr, 0, sizeof(struct sockaddr_un));


addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);

if (connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {


perror("connect");
exit(EXIT_FAILURE);
}

write(sockfd, "Hello from client", 17);

int n = read(sockfd, buf, sizeof(buf));


buf[n] = '\0';
printf("Client received: %s\n", buf);

close(sockfd);
return 0;
}

📌 Notes
 unlink() is important to remove any existing socket file before bind().
 The socket file will be created at the path (e.g., /tmp/unix_stream.sock).
 Use read()/write() or recv()/send() just like TCP.
 Only works locally, not over a network.

✅ Summary
Feature Value
Domain AF_UNIX
Feature Value
Type SOCK_STREAM
Address Filesystem path
Communication Bidirectional and reliable
Use Cases IPC, microservices on same host, supervisor/worker
Performance Faster than TCP/IP

Let's go over a full explanation and example of a Unix Domain Datagram (UDP-like) client-server using
AF_UNIX and SOCK_DGRAM.

🧰 What Are Unix Domain Datagram Sockets?


 Use AF_UNIX and SOCK_DGRAM
 Provide message-oriented, unreliable communication (like UDP)
 Work only on the same host
 Messages are sent and received with bound socket addresses (paths)
 No need to call listen() or accept()

✅ Key Differences from Stream Sockets


Feature SOCK_STREAM SOCK_DGRAM
Connection required? Yes (via connect()/accept()) No
Reliable delivery? Yes No (unordered, unreliable)
Message boundaries? No (byte stream) Yes (each send = 1 message)
Usage Like TCP Like UDP

✅ Functions Used
Function Purpose
socket() Create the socket
bind() Bind to a local socket file
sendto() Send message to remote socket file
recvfrom() Receive message from sender
close() Close socket
unlink() Delete socket file from filesystem

🔧 Server Code – Unix Domain Datagram Socket


c
CopyEdit
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SERVER_PATH "/tmp/unix_dgram_server.sock"

int main() {
int sockfd;
struct sockaddr_un server_addr, client_addr;
socklen_t client_len;
char buf[128];

// Create socket
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}

// Remove previous socket


unlink(SERVER_PATH);

memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, SERVER_PATH, sizeof(server_addr.sun_path) - 1);

// Bind to path
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind");
close(sockfd);
exit(EXIT_FAILURE);
}

printf("Server ready at %s\n", SERVER_PATH);

// Receive message
client_len = sizeof(client_addr);
int n = recvfrom(sockfd, buf, sizeof(buf), 0,
(struct sockaddr *)&client_addr, &client_len);
if (n < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
buf[n] = '\0';
printf("Server received: %s\n", buf);

// Reply to client
sendto(sockfd, "ACK from server", 15, 0,
(struct sockaddr *)&client_addr, client_len);

close(sockfd);
unlink(SERVER_PATH);
return 0;
}

🔧 Client Code – Unix Domain Datagram Socket


c
CopyEdit
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SERVER_PATH "/tmp/unix_dgram_server.sock"


#define CLIENT_PATH "/tmp/unix_dgram_client.sock"

int main() {
int sockfd;
struct sockaddr_un server_addr, client_addr;
char buf[128];

// Create socket
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}

// Bind client to its own unique path


unlink(CLIENT_PATH);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, CLIENT_PATH, sizeof(client_addr.sun_path) - 1);

if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {


perror("bind");
exit(EXIT_FAILURE);
}

// Setup server address


memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, SERVER_PATH, sizeof(server_addr.sun_path) - 1);

// Send message
sendto(sockfd, "Hello from client", 17, 0,
(struct sockaddr *)&server_addr, sizeof(server_addr));
// Receive reply
int n = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
buf[n] = '\0';
printf("Client received: %s\n", buf);

close(sockfd);
unlink(CLIENT_PATH);
return 0;
}

✅ Notes
 The client must bind to a path too, or the server won't know where to reply.
 Use unlink() before bind() to avoid errors if the socket file already exists.
 Datagram sockets do not require connect(), listen(), or accept().

✅ Summary
Feature Value
Domain AF_UNIX
Type SOCK_DGRAM
Addressing Filesystem path (e.g. /tmp/*.sock)
Direction Bidirectional (explicit via sendto/recvfrom)
Connection ❌ Not required
Delivery guarantee ❌ No guarantee (like UDP)
Message boundaries ✅ Preserved

You might also like