Develop
2013.04.23 15:26

[c] Unix Domain Socket 을 이용한 IPC

조회 수 8044 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
Unix Domain Socket(이하 UDS) 는 socket API를 수정없이 이용며, port 기반의 Inernet Domain Socket에 비해서 로컬 시스템의 파일시스템을 이용해서 내부프로세스간의 통신을 위해 사용한다는 점이 다르다고 할수 있다. 

ls 를 이용해서 통신을 위해서 만들어진 파일을 보면 다음과 같은 모습을 보인다.
[yundream@localhost tmp]$ ls -al
srwx------    1 root     nobody          0 12월 14 21:16 .fam_socket

보면 파일타입에 "s" 가 붙어 있는걸 알수 있으며, 파일사이즈가 0으로 되어 있는 걸 알수 있다. 왜냐하면 FIFO와 마찬가지로 메시지가 파일로 쌓이지 않고 커널로 전달되어서 커널에서 처리하기 때문이다.

파일을 통해서 통신을 하며, 커널내부에서 메시지를 관리한다는 점에서 FIFO와 매우 유사한면을 보여주지만, FIFO와는 달리 양방향 통신이 가능하다는 특징을 가지고 있다. 그러므로 다중의 클라이언트를 받아들이는 서버/클라이언트 모델을 만들기가 매우 쉽다.
또한 Inet 소켓을 통한 외부통신에 비해서 2배 이상의 효율을 보여준다라는 장점을 가지고 있다. 

많은 경우 약간 복잡한 내부프로세스간 통신을 해야된다고 했을때 UDS을 많이 사용한다. INET 계층에서의 통신이 TCP/IP 4계층을 모두 거치는것과는 다르게, UDS 은 어플리케이션 계층에서 TCP 계층까지만 메시지가 전달되고, 다시 곧바로 어플리케이션 계층으로 메시지가 올라가게 된다. TCP/IP 계층에 대한 자세한 내용은 TCP/IP 개요(2)를 참고 하기 바란다.

위에서 INET 소켓보다 2배이상의 효율을 가진다고 했는데, 4계층의 레이어를 모두 거쳐야하는 INET 소켓에 비해서 단지 2개의 레이어만 사용한다는 점도 그 이유중 하나로 작용한다.

쏘쓰 코드는 다중연결서버 만들기(1)의 zipcode_multi.c 와 셈플로 알아보는 소켓프로그래밍(1)의 zipcode_cli.c 를 사용하도록할것이다.

예제: zipcode_local.c
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <unistd.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;
    pid_t pid;

    FILE *fp;
    struct sockaddr_un clientaddr, serveraddr;

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

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

    memset(line, '0', 255);
    state = 0;

    if (access(argv[1], F_OK) == 0)
    {
        unlink(argv[1]);
    }
    // 주소 파일을 읽어들인다. 
    client_len = sizeof(clientaddr);
    if((fp = fopen("zipcode.txt", "r")) == NULL)
    {
        perror("file open error : ");
        exit(0);
    }

    // internet 기반의 스트림 소켓을 만들도록 한다. 
    if ((server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error : ");
        exit(0);
    }
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, 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);
    }


    printf("accept : \n");
    while(1)
    {
        client_sockfd = accept(server_sockfd,
            (struct sockaddr *)&clientaddr, &client_len);
        printf("test test\n");
        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);
                    fclose(fp);
                    exit(0);
                }

                if (strncmp(buf, "quit",4) == 0)
                {
                    write(client_sockfd, "bye bye\n", 8);  
                    close(client_sockfd);
                    fclose(fp);
                    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);
            }
        }
    }
    close(client_sockfd);
}


다음은 클라이언트 프로그램이다.
예제: zipcode_cli_local.c
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/socket.h> 
#include <unistd.h> 
#include <sys/un.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>

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

    FILE *fp_in;
    char buf_in[255];
    char buf_get[255];

    struct sockaddr_un clientaddr;

    if (argc != 2)
    {       
        printf("Usage : ./zipcode_cl [file_name]\n");
        printf("예    : ./zipcode_cl /tmp/mysocket\n");
        exit(0);
    }       


    client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_sockfd == -1)
    {
        perror("error : ");
        exit(0);
    }
    bzero(&clientaddr, sizeof(clientaddr));
    clientaddr.sun_family = AF_UNIX;
    strcpy(clientaddr.sun_path, argv[1]);
    client_len = sizeof(clientaddr);
    if (connect(client_sockfd,
        (struct sockaddr *)&clientaddr, client_len) < 0)
    {
        perror("Connect error: ");
        exit(0);
    }
    while(1)
    {
        printf("지역이름 입력 : ");
        fgets(buf_in, 255,stdin);

        buf_in[strlen(buf_in) - 1] = '0';
        write(client_sockfd, buf_in, 255);
        if (strncmp(buf_in, "quit", 4) == 0)
        {
            close(client_sockfd);
            exit(0);
        }
        while(1)
        {
            read(client_sockfd, buf_get, 255); 
            if (strncmp(buf_get, "end", 3) == 0)
                break;

            printf("%s", buf_get);
        }
    }

    close(client_sockfd);
    exit(0);
}

기존의 INET 버젼의 프로그램과 비교해 보면 고작 3줄 정도만 수정되었음을 알수 있을것이다. 단지 소켓 구조체가 sockaddr_un 으로 바뀌고, AF_INET 대신 AF_UNIX 를 그리고 port 번호대신에 파일명을 사용했음을 알수 있다.

나머지의 모든 코드는 INET 코드와 완전히 같다. 그러므로 Unix Domain Socket 를 사용하면 Inet Domain Socket 와 코드 일관성을 유지할수 있으며, 동일한 기술을 사용해서 프로그래밍을 할수 있다. 

또한 다른 대부분의 IPC 설비들이, 범용적으로 사용하기에는 부족한 여러가지 단점들을 가진반면(단방향 이거나, 읽기만 가능하다거나, 제어하기가 어려운) UDS는 매우 범용적인 IPC 로써 사용가능하다라는 장점을 가지고 있다.

실제로 X 서버 같은경우에 외부에서의 접근시에는 INET 연결을 내부에서의 연결을 위해서는 UDS 를 사용한다. 이밖에도 mysql, pgsql, KDE, Gnome 과 같은 대부분의 서버프로그램이 내부통신을 위해서 UDS 를 사용한다.
?

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
409 Develop [ios] Background 에서 네트워크 사용 file hooni 2013.07.22 11598
408 Develop [ios] App States file hooni 2013.07.22 13254
407 Develop [ios] APNS에 사용할 인증서 만들기 (KeyChain에 있는 인증서 Export) file hooni 2015.01.03 992
406 Develop [ios] APNS, Remote Push 수신 시점에서 앱의 3가지 실행 상태 hooni 2018.10.19 1095
405 Develop [ios] APNS, Remote Push 사용자가 수신을 동의했는지 확인하기 hooni 2018.10.19 1372
404 Develop [ios] APNS 클라이언트 구현 (pdf) file hooni 2013.06.27 15835
403 Develop [ios] APNS 샘플 코드.. secret hooni 2013.06.27 0
402 Develop [ios] AES256 알고리즘을 이용해 데이터 암호화/복호화 방법 file hooni 2015.07.21 4192
401 Develop [ios] @property의 속성 (strong, weak, copy) 사용 경우 hooni 2014.08.08 1777
400 Develop [ios] UIView 계층구조 hooni 2015.01.03 1226
399 Develop [html] 캐쉬된 웹페이지 사용하지 않도록 하는 방법 hooni 2003.04.23 13070
398 Develop [html] 메타태그 사용예.. 은지나 바라~ hooni 2003.04.23 7255
397 Develop [html] SVG(Scalable Vector Graphics) 간단 정리 hooni 2014.02.13 8869
396 Develop [html] HTML5 튜토리얼 링크 ㅋㅋ hooni 2013.04.23 12826
395 Develop [git] 쉬운 버전관리 Git 설명 hooni 2015.08.18 963
394 Develop [erp] SAP 모듈 요약 hooni 2013.04.23 15328
Board Pagination Prev 1 ... 26 27 28 29 30 ... 53 Next
/ 53