소켓 프로그래밍을 이용한 웹 서버 구현

작업 설명

Huawei Kunpeng 클라우드 서버의 CentOS 또는 Ubuntu 환경에서 Linux Socket을 사용하여 다음을 구현합니다:

  1. time 서버의 클라이언트와 서버를 작성하고, 실행 화면을 제출하세요.
  2. echo 서버의 클라이언트와 서버를 작성하고, 실행 화면을 제출하세요. 서버는 클라이언트로부터 받은 내용에 "서버 PID 학번 이름 echo:"를 추가하여 반환합니다.
  3. 서버를 Huawei 클라우드 서버에 배포하고, 클라이언트는 Ubuntu 가상 머신을 사용합니다.
  4. 멀티스레드 또는 멀티프로세스를 사용하여 최소 두 개의 클라이언트 연결을 지원해야 합니다.
  5. 서버를 실험 상자에 배포합니다 (가산점 항목).

코드:

클라이언트 코드:

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

#define BUFFER_SIZE 1024
#define ERR_CODE -1

void *send_thread(void *arg) {
    char buffer[BUFFER_SIZE];
    int sock = *(int *)arg;
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
        if (send(sock, buffer, strlen(buffer), 0) == -1) {
            perror("send error");
            break;
        }
    }
    return NULL;
}

void *recv_thread(void *arg) {
    char buffer[BUFFER_SIZE];
    int sock = *(int *)arg;
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        int recv_len = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (recv_len <= 0) {
            if (recv_len == 0) {
                printf("Server closed\n");
                exit(0);
            }
            perror("recv error");
            break;
        }
        printf("\nReceived from server:\n%s", buffer);
    }
    return NULL;
}

int start_client(char *ip_addr, int port) {
    int client_sock;
    struct sockaddr_in server_addr;
    client_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (client_sock == -1) {
        perror("socket creation error");
        return ERR_CODE;
    }
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip_addr);
    if (connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connection error");
        return ERR_CODE;
    }
    pthread_t send_tid, recv_tid;
    if (pthread_create(&send_tid, NULL, send_thread, &client_sock) != 0) {
        perror("thread creation error");
        return ERR_CODE;
    }
    if (pthread_create(&recv_tid, NULL, recv_thread, &client_sock) != 0) {
        perror("thread creation error");
        return ERR_CODE;
    }
    pthread_join(recv_tid, NULL);
    pthread_join(send_tid, NULL);
    close(client_sock);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s IP PORT\n", argv[0]);
        return ERR_CODE;
    }
    int port = atoi(argv[2]);
    char *ip_addr = argv[1];
    start_client(ip_addr, port);
    return 0;
}

서버 코드:

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

#define BUFFER_SIZE 1024
#define ERR_CODE -1

void *handle_client(void *arg) {
    int client_sock = *(int *)arg;
    char buffer[BUFFER_SIZE];
    pid_t pid = getpid();
    char msg_prefix[64];
    sprintf(msg_prefix, "PID %d 학번 이름 echo: ", pid);

    while (1) {
        memset(buffer, 0, BUFFER_SIZE);
        int recv_len = recv(client_sock, buffer, BUFFER_SIZE - 1, 0);
        if (recv_len <= 0) {
            if (recv_len == 0) {
                printf("Client disconnected\n");
                break;
            }
            perror("recv error");
            break;
        }
        strcat(msg_prefix, buffer);
        if (send(client_sock, msg_prefix, strlen(msg_prefix), 0) == -1) {
            perror("send error");
            break;
        }
        memset(msg_prefix, 0, sizeof(msg_prefix));
        sprintf(msg_prefix, "PID %d 학번 이름 echo: ", pid);
    }
    close(client_sock);
    return NULL;
}

int start_server(int port) {
    int server_sock, client_sock;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);
    server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock == -1) {
        perror("socket creation error");
        return ERR_CODE;
    }
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind error");
        return ERR_CODE;
    }
    if (listen(server_sock, 5) == -1) {
        perror("listen error");
        return ERR_CODE;
    }
    while (1) {
        client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &addr_len);
        if (client_sock == -1) {
            perror("accept error");
            continue;
        }
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, &client_sock) != 0) {
            perror("thread creation error");
            close(client_sock);
        }
    }
    close(server_sock);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s PORT\n", argv[0]);
        return ERR_CODE;
    }
    int port = atoi(argv[1]);
    start_server(port);
    return 0;
}

실행 결과:

두 개의 가상 머신을 사용하여 하나는 클라이언트로, 다른 하나는 서버로 작동시킵니다.

서버는 동시에 여러 클라이언트로부터 메시지를 수신할 수 있습니다.

태그: Linux Socket C Programming Multithreading Huawei Cloud Server CentOS

5월 25일 08:44에 게시됨