Open In App

Socket Programming in C

Last Updated : 23 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Socket programming is a way of connecting two nodes on a network to communicate with each other. One socket(node) listens on a particular port at an IP, while the other socket reaches out to the other to form a connection. The server forms the listener socket while the client reaches out to the server.
Socket programming is widely used in instant messaging applications, binary streaming, and document collaborations, online streaming platforms, etc.

Components of Socket Programming

1. Sockets

Sockets are one of the core components used by the program to access the network to communicate with other processes/nodes over the network. It is simply a combination of an IP address and a port number that acts as an endpoint for Communication.
Example: 192.168.1.1:8080, where the two parts separated by the colon represent the IP address( 192.168.1.1 ) and the port number( 8080 ).

Socket Types:

  • TCP Socket (Stream Socket): Provides reliable, connection-based communication (i.e., TCP protocol).
  • UDP Socket (Datagram Socket): Provides connectionless communication, faster but unreliable (i.e., UDP protocol).

2. Client-Server Model

The client-server model refers to the architecture used in socket programming, where a client and a server to interact with each other to exchange information or services. This architecture allows client to send service requests and the server to process and send response to those service requests.

State Diagram for Server and Client Model

State diagram for server and client model of Socket

Socket programming in C is a powerful way to handle network communication.

Creating a Server-Side Process

The server is created using the following steps:

1. Socket Creation

This step involves the creation of the socket using the socket() function.

Parameters:

  • sockfd: socket descriptor, an integer (like a file handle)
  • domain: integer, specifies communication domain. We use AF_ LOCAL as defined in the POSIX standard for communication between processes on the same host. For communicating between processes on different hosts connected by IPV4, we use AF_INET and AF_I NET 6 for processes connected by IPV6.
  • type: communication type
    SOCK_STREAM: TCP(reliable, connection-oriented)
    SOCK_DGRAM: UDP(unreliable, connectionless)
  • protocol: Protocol value for Internet Protocol(IP), which is 0. This is the same number that appears on the protocol field in the IP header of a packet.(man protocols for more details)
C
sockfd = socket(domain, type, protocol)

2. Setsockopt

This helps in manipulating options for the socket referred by the file descriptor sockfd. This is completely optional, but it helps in reuse of address and port. Prevents error such as: “address already in use”.

C
setsockopt(sockfd, level, optname, optval, socklen_t optlen);

3. Bind

After the creation of the socket, the bind() function binds the socket to the address and port number specified in addr(custom data structure). In the example code, we bind the server to the localhost, hence we use INADDR_ANY to specify the IP address.

C++
bind(sockfd, sockaddr *addr, socklen_t addrlen);

Parameters:

  • sockfd: socket file descriptor created using the socket() function.
  • addr: pointer to a struct sockaddr that contains the IP address and port number to bind the socket.
  • addrlen: length of the addr structure.

4. Listen

In this step the server uses the listen() function that puts the server socket in a passive mode, where it waits for the client to approach the server to make a connection. The backlog, defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED.

C
listen(sockfd, backlog);

Parameters:

  • sockfd: socket file descriptor created using the socket() function.
  • backlog: number representing the size of the queue holding the pending connections while the server is waiting to accept a connection.

5. Accept

In this step the server extracts the first connection request from the queue of pending connections for the listening socket, sockfd, creates a new connected socket using the accept() function, and returns a new file descriptor referring to that socket. At this point, the connection is established between client and server, and they are ready to transfer data.

C
new_socket= accept(sockfd, sockaddr *addr, socklen_t *addrlen);

Parameters:

  • sockfd: socket file descriptor returned by socket() and bind().
  • addr: pointer to a struct sockaddr that will be hold the client’s IP address and port number.
  • addrlen: pointer to a variable that specifies the length of the address structure.

6. Send/Recieve

In this step the server can send or receive data from the client .

Send(): to send data to the client

C
send(sockfd, *buf, len, flags);

Parameters:

  • sockfd: socket file descriptor returned by the socket() function.
  • buf: pointer to the buffer containing the data to be sent.
  • len: number of bytes of data to be sent.
  • flags: integer specifying various options for how the data is sent, typically 0 is used for default behavior.

Receive() : to recieve the data from the client.

C
recv( sockfd, *buf, len, flags);

Parameters:

  • sockfd: socket file descriptor returned by the socket() function.
  • buf: pointer to the buffer containing the data to be stored.
  • len: number of bytes of data to be sent.
  • flags: integer specifying various options for how the data is sent, typically 0 is used for default behavior.

6. Close

After the exchange of information is complete, the server closes the socket using the close() function and releases the system resources.

C
close(fd);

Parameters:

  • fd: file descriptor of the socket.

Creating Client-Side Process

Follow the below steps for creating a client-side process:

1. Socket connection

This step involves the creation of the socket which is done in the same way as that of server’s socket creation

2. Connect

The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. Server’s address and port is specified in addr.

C++
connect(sockfd, sockaddr *addr, socklen_t addrlen);

Parameters

  • sockfd: socket file descriptor returned by the socket() function.
  • addr: pointer to struct sockaddr containing the server’s IP address and port number.
  • addrlen: size of the addr.

3. Send/Recieve

In this step the client can send or receive data from the server which is done using the send() and recieve() functions similar to how the server sends/recieves data from the client.

4. Close

Once the exchange of information is complete, the client also needs to close the created socket and releases the system resources using the close() function in the same way as the server does.

Example

In this C program we are exchanging one hello message between server and client to demonstrate the client/server model.

server.c

C
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
int main(int argc, char const* argv[])
{
    int server_fd, new_socket;
    ssize_t valread;
    struct sockaddr_in address;
    int opt = 1;
    socklen_t addrlen = sizeof(address);
    char buffer[1024] = { 0 };
    char* hello = "Hello from server";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET,
                   SO_REUSEADDR | SO_REUSEPORT, &opt,
                   sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr*)&address,
             sizeof(address))
        < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket
         = accept(server_fd, (struct sockaddr*)&address,
                  &addrlen))
        < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
  
    // subtract 1 for the null
    // terminator at the end
    valread = read(new_socket, buffer,
                   1024 - 1); 
    printf("%s\n", buffer);
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    // closing the connected socket
    close(new_socket);
  
    // closing the listening socket
    close(server_fd);
    return 0;
}

client.c

C
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080

int main(int argc, char const* argv[])
{
    int status, valread, client_fd;
    struct sockaddr_in serv_addr;
    char* hello = "Hello from client";
    char buffer[1024] = { 0 };
    if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 and IPv6 addresses from text to binary
    // form
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
        <= 0) {
        printf(
            "\nInvalid address/ Address not supported \n");
        return -1;
    }

    if ((status
         = connect(client_fd, (struct sockaddr*)&serv_addr,
                   sizeof(serv_addr)))
        < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }
  
    // subtract 1 for the null
    // terminator at the end
    send(client_fd, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    valread = read(client_fd, buffer,
                   1024 - 1); 
    printf("%s\n", buffer);

    // closing the connected socket
    close(client_fd);
    return 0;
}


Compiling

gcc client.c -o client
gcc server.c -o server


Output

Client:Hello message sent
Hello from server
Server:Hello from client
Hello message sent

Common Issues and their Fixes in Socket Programming

  • Connection Failures: To avoid connection failures we should ensure that the client is trying to connect to the correct IP address and port.
  • Port Binding Errors: These errors occur when a port is already in use by another application, in this scenario the binding to that port will fail. Try using a different port or close the previous application using the port.
  • Blocking Sockets: By default, sockets are blocking. This means that calls like accept() or recv() will wait indefinitely if there is no client connection or data. You can set the socket to non-blocking mode if needed.


Next Article

Similar Reads