IT_Programming/Network Programming

[펌] fork()를 이용한 다중연결 서버 구현

JJun ™ 2009. 10. 31. 12:07

--------------------------------------------------------------------------------------------------

출처: http://www.joinc.co.kr/

--------------------------------------------------------------------------------------------------

fork 는 다중의 클라이언트를 제어하는 매우 확실한 방법을 제공해준다.
하나의 클라이언트를 처리하다가 문제가 생기더라도 해당 자식프로세스에게만 영향을 끼치므로

전체 서비스에 지장이 생길염려도 없고, 코드역시 다른 select, poll, thread 를 사용하는 것에 비해서

간단하며, 디버깅이 용이 하다라는 장점도 가지고 있다.


거의 유일하다고 생각되는 단점은 자식프로세스를 생성하는데, 많은 시간과 자원이 소모된다는 점과,

어느정도 이상의 자식프로세스를 생성시켰을때 Unix 버젼에 따라서 생성프로세스의 수에 제한이 생긴다는

점이다. 물론 다른 방법들도(select, poll..) 이러한 제한이 있긴하지만, fork 의 경우 좀더 이러한 제한에

신경을 써주어야 한다.

--------------------------------------------------------------------------------------------------

 

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    int server_sockfd, client_sockfd;
    int state, client_len;
    int pid;

    FILE *fp;
    struct sockaddr_in clientaddr, serveraddr;

    char buf[255];
    char line[255];

    if (argc != 2)
    {
        printf("Usage : ./zipcode [port]\n");
        printf("예    : ./zipcode 4444\n");
        exit(0); 
    }

    memset(line, '\0', 255);
    state = 0; // 주소 파일을 읽어들인다.    

    client_len = sizeof(clientaddr);


    if((fp = fopen("zipcode.txt", "r")) == NULL)
    { 
        perror("file open error : ");
        exit(0);
    }

    // internet 스트림 소켓을 만들도록 한다.
    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error : ");
        exit(0);
    }
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1]));

    state = bind(server_sockfd , (struct sockaddr *)&serveraddr,
            sizeof(serveraddr));
    if (state == -1)
    {
        perror("bind error : ");
        exit(0);
    }
   
    state = listen(server_sockfd, 5);
    if (state == -1)
    {
        perror("listen error : ");
        exit(0);
    }
    

    // 해당 시그널 번호에 대한 새로운 시그널 핸들러를 설치한다.

    // (리턴값 - 성공: 시그널 핸들러의 포인터,  실패: SIG_ERR)
    signal(SIGCHLD, SIG_IGN); // SIG_IGN : 시그널을 무시하라.

                                            // SIG_DFL : 시그널 초기 기본 동작을 하게 해주는 옵션
    while(1)
    {
        client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr,
                               &client_len);
        pid = fork();
        if (pid == 0)
        {
            if (client_sockfd == -1)
               {
                perror("Accept error : ");
                exit(0);
            }
            while(1)
            {
                memset(buf, '\0', 255);
                if (read(client_sockfd, buf, 255) <= 0)
                {
                    close(client_sockfd);
                    exit(0);
                }

                if (strncmp(buf, "quit",4) == 0)
                {
                    write(client_sockfd, "bye bye", 8);
                    close(client_sockfd);
                    exit(0);
                    break;
                }

                while(fgets(line,255,fp) != NULL)
                {
                    if (strstr(line, buf) != NULL)
                    {
                        write(client_sockfd, line, 255);
                    }
                    memset(line, '\0', 255);
                }
                write(client_sockfd, "end", 255);
                printf("send end\n");
                rewind(fp);
            }
        }
        if (pid == -1)
        {
            perror("fork error : ");
        }
    }
    close(client_sockfd);
}
 

--------------------------------------------------------------------------------------------------