Understanding Sockets in c

Md Soykot
4 min readSep 1, 2024

--

What is a Socket?

A socket is an essential concept in computer networking, providing a mechanism for programs to communicate over a network. In Unix-based systems, a socket is treated like a file descriptor, an integer representing an open file. This file descriptor can correspond to various types of I/O, including network connections, which allows programs to read from and write to the network similarly to how they interact with files.

Key Concepts

  • File Descriptor: A unique identifier for an open file, which in the context of sockets, represents a network connection.
  • Socket Creation: Sockets are created using the socket() system call, which returns a socket descriptor that can be used for subsequent communication operations.
  • Communication Functions:
  • send() and recv(): Provide fine-grained control over the communication process.
  • read() and write(): Offer a simpler interface, similar to file operations.

Types of Internet Sockets

Internet sockets come in two main types: stream sockets and datagram sockets. Each type has distinct characteristics and uses.

1. Stream Sockets (SOCK_STREAM)

Characteristics:

  • Stream sockets provide reliable, two-way, connection-oriented communication.
  • They ensure that data arrives intact, in order, and without duplicates.

Protocol:

  • Typically use TCP (Transmission Control Protocol), which establishes a connection before data is transferred and guarantees the delivery of packets.

Use Cases:

  • Ideal for applications requiring reliability, such as web browsers (HTTP), remote terminal applications (telnet, ssh), and email (SMTP).

2. Datagram Sockets (SOCK_DGRAM)

Characteristics:

  • Datagram sockets support connectionless communication.
  • They send messages, called datagrams, without establishing a connection, making them faster but less reliable.

Protocol:

  • Use UDP (User Datagram Protocol), which does not guarantee delivery, order, or error-free communication.

Use Cases:

  • Suitable for applications where speed is critical, and occasional data loss is acceptable, such as online games, streaming media (audio and video), and DNS lookups.

Creating a Socket

To create a socket, use the socket() function:

int socket(int domain, int type, int protocol);
  • domain: Specifies the communication domain (e.g., AF_INET for IPv4).
  • type: Specifies the communication type (e.g., SOCK_STREAM or SOCK_DGRAM).
  • protocol: Typically set to 0 to select the default protocol for the given domain and type.

Example:

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

Binding a Socket

Before a socket can accept incoming connections or send data, it must be bound to an address (IP address and port number):

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

Example:

struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);

if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}

Listening and Accepting Connections (for Stream Sockets)

For stream sockets, the server must listen for incoming connections and accept them:

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

Example:

if (listen(sockfd, 5) < 0) {
perror("listen failed");
close(sockfd);
exit(EXIT_FAILURE);
}

int newsockfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);
if (newsockfd < 0) {
perror("accept failed");
close(sockfd);
exit(EXIT_FAILURE);
}

Sending and Receiving Data

Data can be sent and received using send() and recv() for finer control:

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

Or using read() and write() for a simpler interface:

ssize_t read(int sockfd, void *buf, size_t count);
ssize_t write(int sockfd, const void *buf, size_t count);

Example Code

TCP Server

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFSIZE 1024
int main() {
int sockfd, newsockfd;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
char buffer[BUFSIZE];
int n;
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Bind socket
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}
// Listen
if (listen(sockfd, 5) < 0) {
perror("listen failed");
close(sockfd);
exit(EXIT_FAILURE);
}
// Accept
clilen = sizeof(cliaddr);
newsockfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);
if (newsockfd < 0) {
perror("accept failed");
close(sockfd);
exit(EXIT_FAILURE);
}
// Receive and echo data
while ((n = read(newsockfd, buffer, BUFSIZE)) > 0) {
buffer[n] = '\\0';
printf("Client: %s", buffer);
write(newsockfd, buffer, n);
}
close(newsockfd);
close(sockfd);
return 0;
}

TCP Client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFSIZE 1024
int main() {
int sockfd;
struct sockaddr_in servaddr;
char buffer[BUFSIZE];
int n;
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Set server address
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) {
perror("invalid address");
close(sockfd);
exit(EXIT_FAILURE);
}
// Connect to server
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("connect failed");
close(sockfd);
exit(EXIT_FAILURE);
}
// Send and receive data
while (fgets(buffer, BUFSIZE, stdin) != NULL) {
write(sockfd, buffer, strlen(buffer));
n = read(sockfd, buffer, BUFSIZE);
buffer[n] = '\\0';
printf("Server: %s", buffer);
}
close(sockfd);
return 0;
}

Conclusion

Sockets are a fundamental aspect of network programming, providing a versatile interface for communication over networks. Whether you’re developing a simple chat application, a complex web server, or a real-time multiplayer game, understanding and effectively using sockets is crucial. By mastering the concepts and functions related to sockets, you can create robust and efficient networked applications.

--

--

Md Soykot
Md Soykot

Written by Md Soykot

Software Engineer | Frontend Expert | R&D | Problem Solver | Automation Enthusiast

Responses (1)