Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình C

Xây dựng Server Socket đa tiến trình trong C dùng Fork

Xây dựng Server Socket đa tiến trình trong C dùng Fork

Server socket đa tiến trình với fork trong C cho phép xử lý đồng thời nhiều kết nối client. Bằng cách dùng system call fork(), server tạo tiến trình con cho mỗi client kết nối, đảm bảo kênh giao tiếp độc lập. Cách này cho phép giao tiếp đồng thời với nhiều client.

System call fork() là gì?

Khi system call tạo bản sao của tiến trình hiện tại, gọi là fork(). Nó tách chương trình thành hai tiến trình riêng biệt: cha và con. Tất cả tham số giống nhau trừ PID. fork() trả về:

  1. PID của tiến trình con cho tiến trình cha.
  2. 0 cho tiến trình con.

Ví dụ 1: Chương trình Server

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

#define PORT 8888

int main() {
    int serSoc, cliSoc;
    struct sockaddr_in serverAddr, clientAddr;
    socklen_t addrSize = sizeof(clientAddr);
    char buffer[1024];
    int clientCount = 0;

    // Tạo socket server
    serSoc = socket(AF_INET, SOCK_STREAM, 0);
    if (serSoc < 0) {
        perror("Error in socket creation");
        exit(1);
    }
    printf("Server socket created.\n");

    // Thiết lập địa chỉ server
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(serSoc, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("Error in binding");
        exit(1);
    }

    // Lắng nghe kết nối
    if (listen(serSoc, 5) == 0) {
        printf("Listening for connections...\n");
    } else {
        perror("Error in listening");
        exit(1);
    }

    while (1) {
        // Chấp nhận kết nối client
        cliSoc = accept(serSoc, (struct sockaddr*)&clientAddr, &addrSize);
        if (cliSoc < 0) {
            perror("Error in accepting connection");
            exit(1);
        }

        clientCount++;
        printf("Accepted connection from Client %d: %s:%d\n", clientCount,
               inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
        printf("Total clients connected: %d\n", clientCount);

        pid_t pid = fork();

        if (pid == 0) {
            // Tiến trình con
            close(serSoc);

            while (1) {
                memset(buffer, 0, sizeof(buffer));
                if (recv(cliSoc, buffer, sizeof(buffer), 0) < 0) {
                    perror("Error in receiving data");
                    exit(1);
                }
                printf("Received data from Client %d: %s\n", clientCount, buffer);

                // Echo lại cho client
                if (send(cliSoc, buffer, strlen(buffer), 0) < 0) {
                    perror("Error in sending data");
                    exit(1);
                }
            }
        } else if (pid > 0) {
            // Tiến trình cha
            close(cliSoc);
        } else {
            perror("Error in forking");
            exit(1);
        }
    }

    close(serSoc);
    return 0;
}

Ví dụ 2: Chương trình Client

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

#define PORT 8888
#define SERVER_IP "127.0.0.1"

int main() {
    int cliSoc;
    struct sockaddr_in serverAddr;
    char buffer[1024];

    cliSoc = socket(AF_INET, SOCK_STREAM, 0);
    if (cliSoc < 0) {
        perror("Error in socket creation");
        exit(1);
    }
    printf("Client %d socket created.\n", getpid());

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);

    if (connect(cliSoc, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("Error in connecting to server");
        exit(1);
    }
    printf("Connected to server.\n");

    while (1) {
        printf("Client %d - Enter a message: ", getpid());
        fgets(buffer, sizeof(buffer), stdin);

        if (send(cliSoc, buffer, strlen(buffer), 0) < 0) {
            perror("Error in sending data");
            exit(1);
        }

        memset(buffer, 0, sizeof(buffer));
        if (recv(cliSoc, buffer, sizeof(buffer), 0) < 0) {
            perror("Error in receiving data");
            exit(1);
        }
        printf("Client %d - Server response: %s\n", getpid(), buffer);
    }

    close(cliSoc);
    return 0;
}

Kết quả chạy

**Server program compilation**
$ gcc ser.c -o ser
$ ./ser
Server socket created.
Listening for connections...
Server socket created.
Listening for connections...
Accepted connection from Client 1: 127.0.0.1:59074
Total clients connected: 1
Received data from Client 1: hii admin
Accepted connection from Client 2: 127.0.0.1:40192
Total clients connected: 2
Received data from Client 2: hello everybody

**Client 1 program compilation**
$ gcc cel.c -o cel
$ ./cel
Client 4007 socket created.
Connected to server.
Client 4007 - Enter a message: hii admin

**Client 2 program compilation**
$ gcc cel.c -o cel
$ ./cel
Client 4024 socket created.
Connected to server.
Client 4024 - Enter a message: hello everybody

Giải thích

Server tạo socket, bind, listen. Khi client kết nối, fork() tạo tiến trình con xử lý client đó, cho phép xử lý đồng thời nhiều client. Tiến trình con nhận dữ liệu, hiển thị kèm ID client và echo lại. Mô hình này hỗ trợ giao tiếp đồng thời với n client.

Kết luận

Đã triển khai server socket đa tiến trình dùng fork() trong C, cho phép xử lý đồng thời nhiều kết nối client hiệu quả.

Tác giả

Xây dựng Server Socket đa tiến trình trong C dùng Fork

Bamdeb Ghosh

Chuyên gia mạng không dây, phân tích Wireshark, am hiểu Android, Bluetooth, Linux, Python. Trang web: wifisharks.com