유닉스(Unix)/네트워크 프로그래밍

TCP 에코 서버 프로그램

ddingz 2022. 1. 5. 18:20

tcp_echoserv.c

TCP 소켓을 이용하여 에코 서비스를 제공하는 서버 프로그램이다.
tcp_echoserv.c는 클라이언트의 접속요청을 수락한 후 바로 에코 서비스를 수행한다.
이 서버를 이용할 클라이언트 프로그램으로는 tcp_echocli.c를 사용하면 된다.

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

#define MAXLINE 127

int main(int argc, char *argv[]) {
    struct sockaddr_in servaddr, cliaddr;
    int listen_sock;
    int accp_sock; // 소켓번호
    int addrlen = sizeof(cliaddr); // 소켓주소 구조체 길이
    int nbyte;
    char buf[MAXLINE + 1];

    if (argc != 2) {
        printf("usage: %s port\n", argv[0]);
        exit(0);
    }

    // 소켓 생성
    if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("sock fail");
        exit(0);
    }

    // servaddr을 '\0'으로 초기화
    bzero((char *)&servaddr, sizeof(servaddr));

    // servaddr 세팅
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(atoi(argv[1]));

    // bind() 호출
    if (bind(listen_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind fail");
        exit(0);
    }

    // 소켓을 수동 대기모드로 세팅
    listen(listen_sock, 5);

    // iterative 에코 서비스 수행
    while (1) {
        puts("서버가 연결요청을 기다림..");

        // 연결요청을 기다림
        accp_sock = accept(listen_sock, (struct sockaddr *)&cliaddr, &addrlen);
        if (accp_sock < 0) {
            perror("accept fail");
            exit(0);
        }
        puts("클라이언트가 연결됨..");
        nbyte = read(accp_sock, buf, MAXLINE);
        write(accp_sock, buf, nbyte);

        close(accp_sock);
    }

    close(listen_sock);

    return 0;
}

서버는 accept() 함수에서 기다리게 된다.
이때 어떤 클라이언트의 접속요청이 수신되면 accept()는 새로운 소켓(accp_sock)을 생성하며 리턴한다.
accept()는 또한 접속된 클라이언트의 소켓주소 정보를 두 번째 인자(아래의 cliaddr)를 통하여 알려준다.

accp_sock = accept(listen_sock, (struct sockaddr *)&cliaddr, &addrlen);

서버는 클라이언트가 보내오는 데이터를 read()로 읽고 write()로 에코하는데 이때 accept()가 리턴한 소켓번호 accp_sock를 사용하여야 한다.
즉, listen_sock는 서버가 새로운 클라이언트의 연결요청을 받기 위한 소켓번호이며 일단 연결된 클라이언트와는 accept()가 리턴한 소켓번호를 사용하여 통신해야 한다.


실행 결과