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.
#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;
}
Learn how to assign an address to a socket and understand the generic sockaddr structure.
