CLOSE
Updated on 17 Jun, 202513 mins read 4 views

In this chapter, we delve into the core C/C++ system calls and functions that power socket programming. These are the building blocks that allow us to send and receive data over a network.

Every networking program in C/C++—whether it’s a web server, a chat client, or a file transfer application—relies heavily on these key socket APIs.

Flow of Socket Program

Before going deeper, here's the overall flow of a typical socket program.

For Server:

socket() → bind() → listen() → accept() → recv()/send() → close()

For Client:

socket() → connect() → send()/recv() → close()

1️⃣ Socket()

Purpose:

Creates a socket, which is an endpoint for communication.

Syntax:

int socket(int domain, int type, int protocol);

Parameters:

  • domain: Address family (usually AF_INET for IPv4 or AF_INET6 for IPv6)
  • type: Type of socket (e.g., SOCK_STREAM for TCP, SOCK_DGRAM for UDP(
  • protocol: Usually set to 0 (auto-select)

Example:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
    perror("socket creation failed");
    exit(EXIT_FAILURE);
}

📍 2️⃣ bind()

Purpose:

Associates the socket with a local IP address and port number.

Syntax:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Parameters:

  • sockfd: Socket file descriptor
  • addr: Pointer to a a sockaddr_in structure (cast to sockaddr*)
  • addrlen: Size of addr structure

Example:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);  // Port 8080
server_addr.sin_addr.s_addr = INADDR_ANY;  // Any local IP

bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

📡 3️⃣ listen()

Purpose:

Marks a socket as passive, ready to accept incoming connection (TCP only).

Syntax:

int listen(int sockfd, int backlog);

Parameters:

  • sockfd: Socket file descriptor
  • backlog: Maximum number of pending connections

Example:

listen(sockfd, 5);  // Queue up to 5 pending connections

🤝 4️⃣ accept()

Purpose:

Accepts a new incoming connection request.

Syntax:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Parameters:

  • sockfd: The listening socket
  • addr: Populated with client's address
  • addrlen: Pointer to length of the address structure

Example:

struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);

int client_sock = accept(sockfd, (struct sockaddr*)&client_addr, &len);
if (client_sock < 0) {
    perror("accept failed");
    exit(EXIT_FAILURE);
}

🔗 5️⃣ connect() (client side)

Purpose:

Initiates a connection to a remote server (used on the client side).

Syntax:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Example:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

📤 6️⃣ send() and recv()

send()

Sends data on connected socket (TCP).

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

recv()

Received data from a connected socket.

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

Example:

char buffer[1024];
send(client_sock, "Hello from server", 17, 0);
recv(client_sock, buffer, sizeof(buffer), 0);

7️⃣ sendto() and recvfrom() (for UDP)

used with connectionless protocols like UDP.

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

🧹 8️⃣ close()

Purpose:

Closes the socket file descriptor.

Example:

close(sockfd);

Error Handling

Most socket functions return -1 on error and set the global errno. Always check return values and use perror() or strerror() for debugging.

if (connect(sockfd, ...) < 0) {
    perror("Connection failed");
    exit(EXIT_FAILURE);
}