Section 56.2 – socket()
Before two processes can communicate using sockets, at least one of them must create a socket. This is done using the socket() system call. Think of it as manufacturing a telephone handset — you need one before you can make or receive any calls.
Key Terms in This Part
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
/* Returns: file descriptor (non-negative) on success, -1 on error */
| Argument | Type | What it controls | Common values |
|---|---|---|---|
domain |
int | Communication domain / address family | AF_UNIX, AF_INET, AF_INET6 |
type |
int | Socket type (can OR with flags) | SOCK_STREAM, SOCK_DGRAM |
protocol |
int | Specific protocol (usually 0) | 0, IPPROTO_RAW |
1. domain
Specifies where the communication happens and what address format is used. The most common values are AF_UNIX (same machine, pathname address), AF_INET (IPv4 network), and AF_INET6 (IPv6 network).
2. type
Specifies how data flows. The two standard values are:
SOCK_STREAM– reliable, ordered, connection-based byte stream (TCP)SOCK_DGRAM– unreliable, connectionless, preserves message boundaries (UDP)
Since Linux kernel 2.6.27, you can also bitwise-OR additional flags into type (explained below).
3. protocol
For the socket types covered in this chapter, always pass 0. The kernel picks the appropriate protocol automatically. You only set a non-zero value for special cases like raw sockets (IPPROTO_RAW).
On success, socket() returns a new file descriptor — a small non-negative integer just like the fd returned by open(). This fd is used in all subsequent socket system calls (bind(), connect(), send(), recv(), etc.).
On failure, socket() returns -1 and sets errno.
The fd is now ready to be used with bind(), connect(), etc.
Starting from kernel 2.6.27, Linux allows you to OR two extra flags into the type argument. This saves extra fcntl() calls that you would otherwise need after creating the socket.
Sets the FD_CLOEXEC (close-on-exec) flag on the new socket fd.
Why useful: When a process calls exec() to run a new program, all file descriptors that do NOT have this flag will be inherited. If your server creates a socket and then spawns a child with exec(), you usually do NOT want the child to inherit the socket. SOCK_CLOEXEC prevents this automatically and race-free.
Sets the O_NONBLOCK flag on the underlying open file description.
Why useful: Normally I/O calls on a socket block if data is not ready. With this flag, they return immediately with EAGAIN / EWOULDBLOCK if no data is available. Useful in event-driven (non-blocking) server designs like those using epoll.
Example 1: Basic TCP socket creation
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
int main(void)
{
int sockfd;
/* Create an IPv4 TCP stream socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("Socket created successfully, fd = %d\n", sockfd);
/* sockfd is now ready for bind() or connect() */
close(sockfd);
return 0;
}
Example 2: UDP socket (datagram)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
int main(void)
{
int sockfd;
/* Create an IPv4 UDP datagram socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("UDP socket fd = %d\n", sockfd);
close(sockfd);
return 0;
}
Example 3: Using SOCK_CLOEXEC and SOCK_NONBLOCK flags
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
int main(void)
{
int sockfd;
/*
* Create TCP socket with two extra flags OR-ed in:
* SOCK_CLOEXEC – auto-close on exec(), avoids race with fork+exec
* SOCK_NONBLOCK – I/O calls return EAGAIN instead of blocking
*
* Requires Linux kernel >= 2.6.27
*/
sockfd = socket(AF_INET,
SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("Non-blocking, close-on-exec TCP socket fd = %d\n", sockfd);
close(sockfd);
return 0;
}
Example 4: UNIX domain socket (same-machine IPC)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
int main(void)
{
int sockfd;
/* AF_UNIX = local IPC via filesystem path, no network needed */
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("UNIX domain socket fd = %d\n", sockfd);
close(sockfd);
return 0;
}
Example 5: Equivalent using fcntl() (the old way)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/socket.h>
int main(void)
{
int sockfd, flags;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) { perror("socket"); exit(1); }
/* Set O_NONBLOCK using fcntl (old method, two extra syscalls) */
flags = fcntl(sockfd, F_GETFL);
if (flags == -1) { perror("fcntl F_GETFL"); exit(1); }
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl F_SETFL");
exit(1);
}
/*
* The SOCK_NONBLOCK flag at socket() creation avoids these
* two extra fcntl() calls shown above.
*/
printf("Non-blocking socket fd = %d (done via fcntl)\n", sockfd);
close(sockfd);
return 0;
}
Q1. What does the socket() system call return?It returns a file descriptor (a non-negative integer) on success, or -1 on error. This fd is used in all subsequent socket operations just like a regular file descriptor.
Q2. What should you pass as the protocol argument in socket()?For the common socket types (SOCK_STREAM, SOCK_DGRAM), always pass 0. The kernel automatically selects the correct protocol (TCP for SOCK_STREAM over AF_INET, UDP for SOCK_DGRAM over AF_INET). Non-zero values like IPPROTO_RAW are only needed for raw sockets.
Q3. What is SOCK_CLOEXEC and why is it useful?SOCK_CLOEXEC sets the FD_CLOEXEC flag on the socket fd at creation time. This causes the fd to be automatically closed when the process calls exec(). Without it, a child process spawned via fork+exec would inherit the socket fd, which is usually undesirable in server programs. Using SOCK_CLOEXEC also avoids a race condition that would exist if you first create the socket and then set FD_CLOEXEC separately.
Q4. What is SOCK_NONBLOCK? How is it different from calling fcntl() after socket()?SOCK_NONBLOCK sets O_NONBLOCK on the underlying open file description at socket creation time. With O_NONBLOCK set, I/O calls return EAGAIN/EWOULDBLOCK immediately instead of blocking when data is not ready. Using the flag at socket() creation saves two extra fcntl() system calls (F_GETFL + F_SETFL) that you would otherwise need. It is equivalent in effect but more efficient and race-free.
Q5. From which kernel version are SOCK_CLOEXEC and SOCK_NONBLOCK available?Linux kernel 2.6.27 and later. On older kernels you must use fcntl() after socket() to set these properties.
Q6. What is the difference between socket() and open()?Both return a file descriptor. open() creates/opens a file in the filesystem. socket() creates a communication endpoint. A socket fd supports I/O operations like read/write but also socket-specific calls (bind, connect, listen, accept, send, recv). A socket has no name in the filesystem by default until bind() is called (for AF_UNIX sockets).
Q7. Can you use read() and write() on a socket fd?Yes. Because a socket is a file descriptor, standard read() and write() work on it. However, socket-specific calls like send() and recv() are preferred because they accept a flags argument that enables features like MSG_PEEK (look without consuming), MSG_DONTWAIT (non-blocking for one call), and MSG_WAITALL (wait for full buffer).
