Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

  • 우선 간단히 정리 - 2010/2/24

이유

윈도 환경에서 소켓(:12), thread(:12) 프로그래밍을 하려니 짜증이 밀려온다. 도대체 왜 POSIX(:12) 표준 API를 내비두고 자기들만의 API를 제공하는 건데.

특히 thread 부분에서 짜증이 난다. 해서 cygwin을 설치 해서 사용해 보기로 했다. cygwin으로 그럴듯한 개발환경 구축할 수 있다는 얘기를 들은 기억도 있고 해서다.

cygwin

  1. cygwin은 리눅스(:12) 애플리케이션을 윈도에서 실행하도록 해주는 애물레이션 같은 툴이 아니다.
  2. virtualbox와 같은 가상화 도구도 아니다.
  3. cygwin은 리눅스와 같은 개발환경을 만들어 준다.
    • cygwin1.dll로 리눅스 API 애뮬레이터 계층을 만든다. 이 계층은 리눅스 함수들을 포함한다.
    • 리눅스에서 사용하는 여러가지 프로그램을 사용할 수 있다. 여기에는 "쉘",/bin, /usr/bin밑에 있는 각종 리눅스 프로그램이 포함된다.
    • 리눅스와 같은 디렉토리/파일 체계를 사용한다.
  4. 소켓, IPC, pthread 등 리눅스의 프로그래밍 기술을 그대로 사용할 수 있다. 그러나 운영체제의 차이를 완전히 극복해주는 마법을 구사하지는 않는다.
    • 리눅스의 시그널과 윈도의 시그널은 상당히 다르다. cygwin으로 리눅스의 시그널을 사용할 수는 있지만 그 차이를 고려해야 한다.
    • ipc역시 많은 차이를 보인다. cygwin은 별도의 서버 프로그램을 실행 시켜서 ipc 서비스를 제공한다.
  5. 설치

    • http://cygwin.com 에서 온라인으로 설치할 수 있다. "install or update now"를 클릭하면 셋업 프로그램이 실행된다. cygwin의 설치는 물론 gcc, vi 등과 같은 각종 리눅스 애플리케이션을 설치할 수 있다.
    • 설치 과정은 따로 정리 : 간단하긴 하지만..
    설치후 bash 쉘에서 vi(:12)를 실행시켜서 간다한 쓰레드 프로그램을 만들어 보았다.

    프로그래밍 이슈들

    pthread 프로그래밍

    pthread의 각 함수들이 예상한 대로 작동하는지 확인하기 위한 간단한 프로그램
    #include <stdio.h>  
    #include <unistd.h>  
    #include <pthread.h>  
     
    int ncount;    // 쓰레드간 공유되는 자원 
    pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER; // 쓰레드 초기화 
     
    void* do_loop(void *data) 
    { 
        int i; 
     
        for (i = 0; i < 10; i++) 
        { 
            pthread_mutex_lock(&mutex); // 잠금을 생성한다. 
            printf("loop1 : %d\n", ncount); 
            ncount ++; 
            sleep(1); 
            pthread_mutex_unlock(&mutex); // 잠금을 해제한다. 
            usleep(10);
        } 
    } 
     
    void* do_loop2(void *data) 
    { 
        int i; 
     
        // 잠금을 얻으려고 하지만 do_loop 에서 이미 잠금을  
        // 얻었음으로 잠금이 해제될때까지 기다린다.   
        for (i = 0; i < 10; i++) 
        { 
            pthread_mutex_lock(&mutex); // 잠금을 생성한다. 
            printf("loop2 : %d\n", ncount); 
            ncount ++; 
            sleep(1); 
            pthread_mutex_unlock(&mutex); // 잠금을 해제한다. 
            usleep(10);
        } 
    }     
     
    int main() 
    { 
        int       thr_id; 
        pthread_t p_thread[2]; 
        int status; 
        int a = 1; 
     
        ncount = 0; 
        thr_id = pthread_create(&p_thread[0], NULL, do_loop, (void *)&a); 
        sleep(1); 
        thr_id = pthread_create(&p_thread[1], NULL, do_loop2, (void *)&a); 
     
        pthread_join(p_thread[0], (void *) &status); 
        pthread_join(p_thread[1], (void *) &status); 
     
        status = pthread_mutex_destroy(&mutex); 
        printf("code  =  %d", status); 
        printf("programing is end"); 
        return 0; 
    } 
    쓰레드 생성, 뮤텍스(:12) 모두 잘 작동한다. 윈도 쓰레드와 비슷하니 크게 문제가 생길 것 같지 않다는 생각은 든다.

    BSD 소켓 프로그래밍

    소켓의 경우 winsock(:12)이 BSD:::socket(:12) 인터페이스를 그대로 따르고 있기 때문에, cygwin을 사용하지 않아도 비교적 쉽게 포팅이 가능하다. 하지만 파일 지정 번호를 다루는 BSD 소켓과 핸들을 다루는 윈속의 차이 때문에 귀찮은 작업이 필요하다. cygwin으로 BSD 소켓 인터페이스를 그대로 사용할 수 있는지 확인해 봤다.

    간단한 에코 서버 프로그램을 만들었다.
    #include <sys/socket.h> 
    #include <sys/stat.h> 
    #include <arpa/inet.h> 
    #include <stdio.h> 
    #include <string.h> 
     
    #define MAXBUF  256 
    int main(int argc, char **argv) 
    { 
        int server_sockfd, client_sockfd; 
        int client_len, n; 
        char buf[MAXBUF]; 
        struct sockaddr_in clientaddr, serveraddr; 
     
        client_len = sizeof(clientaddr); 
     
        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])); 
     
        bind (server_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); 
        listen(server_sockfd, 5); 
     
        while(1) 
        { 
            memset(buf, 0x00, MAXBUF); 
            client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr, 
                                &client_len); 
     
            if ((n = read(client_sockfd, buf, MAXBUF)) <= 0) 
            { 
                close(client_sockfd); 
                continue; 
            } 
            if (write(client_sockfd, buf, MAXBUF) <=0) 
            { 
                perror("write error : "); 
                close(client_sockfd); 
            } 
            close(client_sockfd); 
        } 
    } 
    잘 된다. 편하다.

    윈속과 거의 동일한 인터페이스를 가지고 있으니, 복잡한 프로그램이라도 문제 없이 작동하리라 예상한다.

    멀티 프로세스

    윈도는 fork(2)시스템 호출이 없다. CreateProcess(:4200)가 있기는 하지만 fork(2)와는 개념이 좀 다르다.

    IPC

    System V / POSIX(:12) IPC(:12) 모두에 대해서 테스트 해봐야 겠다.

    signal

    시그널은 개념이 꽤나 다른데, 잘 될까 ?

    윈도 네이티브 프로그램 개발

    이 것도 한번 해봐야지.