Chat client in c

Learn chat client in c with practical examples, diagrams, and best practices. Covers c development techniques with visual explanations.

Building a Simple Chat Client in C: A Step-by-Step Guide

Hero image for Chat client in c

Learn the fundamentals of network programming in C by creating a basic command-line chat client. This guide covers socket creation, connection, and data exchange.

Developing a chat client is an excellent way to grasp the core concepts of network programming. This article will walk you through building a simple command-line chat client using the C programming language. We'll focus on the client-side logic, including establishing a connection to a server, sending messages, and receiving messages. While this example won't include a server, the client will be capable of connecting to any compatible TCP server.

Understanding Network Sockets

At the heart of network communication in C are sockets. A socket is an endpoint for sending or receiving data across a network. Think of it as one end of a telephone connection. For our chat client, we'll primarily use TCP (Transmission Control Protocol) sockets, which provide reliable, ordered, and error-checked delivery of a stream of bytes between applications. This is crucial for ensuring chat messages arrive intact and in the correct sequence.

flowchart TD
    A[Client Application] --> B{socket() call}
    B --> C[Socket Descriptor]
    C --> D{connect() call}
    D --> E[Server IP:Port]
    E --> F[Connection Established]
    F --> G{send() / recv() calls}
    G --> H[Data Exchange]
    H --> I{close() call}
    I --> J[Connection Closed]

Basic TCP Client Connection Flow

Setting Up the Client Socket

The first step for our client is to create a socket and then attempt to connect to a server. This involves several system calls: socket(), inet_addr(), htons(), and connect(). The socket() function creates a new communication endpoint. inet_addr() converts an IP address string into a network address structure. htons() ensures the port number is in network byte order. Finally, connect() attempts to establish a connection to the specified server.

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

#define PORT 8080
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};

    // 1. Create socket file descriptor
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation error");
        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, SERVER_IP, &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        return -1;
    }

    // 2. Connect to the server
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection Failed");
        return -1;
    }

    printf("Connected to server %s:%d\n", SERVER_IP, PORT);

    // ... (send/receive logic will go here)

    close(sock);
    return 0;
}

Initial client setup: socket creation and connection.

Sending and Receiving Messages

Once connected, the client needs to be able to send messages to the server and receive messages from it. This typically involves a loop where the client can continuously read user input, send it, and also listen for incoming messages. We'll use send() to transmit data and recv() to receive data. To handle both sending and receiving concurrently, a common approach is to use select() or create separate threads.

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

#define PORT 8080
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024

int client_sock = 0;

// Function to receive messages from the server
void *receive_messages(void *arg) {
    char buffer[BUFFER_SIZE];
    int valread;
    while (1) {
        memset(buffer, 0, BUFFER_SIZE);
        valread = recv(client_sock, buffer, BUFFER_SIZE, 0);
        if (valread <= 0) {
            printf("Server disconnected or error.\n");
            break;
        }
        printf("Server: %s\n", buffer);
    }
    return NULL;
}

int main() {
    struct sockaddr_in serv_addr;
    char message[BUFFER_SIZE];
    pthread_t recv_thread;

    // 1. Create socket file descriptor
    if ((client_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation error");
        return -1;
    }

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

    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        return -1;
    }

    // 2. Connect to the server
    if (connect(client_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection Failed");
        return -1;
    }

    printf("Connected to server %s:%d\n", SERVER_IP, PORT);
    printf("Type 'exit' to quit.\n");

    // Create a separate thread for receiving messages
    if (pthread_create(&recv_thread, NULL, receive_messages, NULL) != 0) {
        perror("Failed to create receive thread");
        close(client_sock);
        return -1;
    }

    // Main thread for sending messages
    while (1) {
        printf("You: ");
        fgets(message, BUFFER_SIZE, stdin);
        message[strcspn(message, "\n")] = 0; // Remove newline character

        if (strcmp(message, "exit") == 0) {
            break;
        }

        send(client_sock, message, strlen(message), 0);
    }

    // Clean up
    pthread_cancel(recv_thread); // Cancel the receive thread
    pthread_join(recv_thread, NULL); // Wait for the thread to terminate
    close(client_sock);
    printf("Disconnected.\n");

    return 0;
}

Full chat client with separate thread for receiving messages.

1. Compile the Client

Save the code as client.c. Compile it using a C compiler like GCC: gcc client.c -o client -pthread.

2. Run a Compatible Server

Before running the client, ensure you have a TCP server listening on 127.0.0.1:8080. You can use a simple Python server or a C server for testing.

3. Execute the Client

Run the compiled client from your terminal: ./client. It should connect to the server, and you can start typing messages.

4. Test Communication

Type messages into the client, and they will be sent to the server. Any messages sent from the server will appear in the client's console.