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

  • syslog 소개 문서에서 이어짐
  • wiki 스타일에 맞게 수정해야함.
  • 내용도 너무 오래 되었음 수정해야함. 이제 memrecver 에 소켓연결후 syslog 메시지를 전송하는 memsender 를 제작해 보도록하자, 보통의 파일을 열어서 읽은 다음에 소켓으로 전송하는 일반적인 루틴을 가지고 있지만, 파일의 마지막라인을 만나더라도, 파일 연결지시자를 계속 유지하고 있다가 새로운 내용이 추가되면 다시 read 해야 하므로(이를테면 tail 에 -f 옵션을 준것과 비슷한), select(2) 를 통해서 이를 구현하도록 하겠다.
    select 는 입출력다중화를 위한 목적으로 주로 쓰이며, 네트웍 프로그래밍에서 다중 클라이언트를 받아들이는 서버제작 기법으로 많이 활용된다.

    예제: memsender.c
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define PORT 12345
    #define PACKET_SIZE 255
    
    int main()
    {
        int fd;
        int n;
        int state;
        int client_len;
        int client_sockfd;
        int i;
        FILE *fp;
        char *buf;
    
        char l_buf[1];
    
        struct sockaddr_in clientaddr;
        struct timeval tv;
    
        fd_set readfds;
    
        if((fd = open("/var/log/meminfo", O_RDONLY)) == -1)
        {
            perror("file open error : ");
            exit(0);
        }
    
    
        // memrecver 서버에 연결을 위한 소켓생성및 연결
    
        client_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        clientaddr.sin_family = AF_INET;
        clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        clientaddr.sin_port = htons(PORT);
    
        client_len = sizeof(clientaddr);
    
        if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) < 0)
        {
            perror("connect error : ");
            exit(0);
        }
    
        fp = fdopen(fd, "w");
        buf = (char *)malloc(PACKET_SIZE);
        i = 0;
        while(1)
        {
            tv.tv_sec = 0;
            tv.tv_usec = 10000;
    
            state = select(2, &readfds, (fd_set *)0, (fd_set *)0, &tv);
    
            switch(state)
            {
                case -1:
                    perror("select error : ");
                    exit(0);
    
                default :
                    memset(buf, 0x00, PACKET_SIZE);
                    while ((n = read(fd, l_buf, 1)) > 0)
                    memset(buf, 0x00, PACKET_SIZE);
                    while ((n = read(fd, l_buf, 1)) > 0)
                    {
                        buf[i] = l_buf[0];
                        if (l_buf[0] == '\n')
                        {
                            write(client_sockfd, buf, i+1);
                            printf("-->%s", buf);
                            memset(buf, 0x00, PACKET_SIZE);
                            i = 0;
                            continue;
                        }
                        i++;
                    }
                    break;
            }
        }
        close(fd);
    }
    
    select 가 들어간것만 빼고는 매우 일반적인 프로그램이므로 설명은 생략하도록 하겠다.
    소켓관련 프로그래밍은 셈플로 알아보는 소켓프로그래밍(1)을 >참고하기 바란다.

    예제: memrecever.c
    #include <sys/types.h>
    #include <stdio.h>
    #include <unistd.h> 
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <sys/stat.h> 
    #include <netinet/in.h>
    #include <arpa/inet.h> 
    #include <fcntl.h> 
    
    #define SA struct sockaddr
    #define PACKET_SIZE 255 
    
    const char *needle = ": ";
    
    int main(int argc, char **argv)
    {
        int server_sockfd, client_sockfd;
        int state, clilen;
        int n;
    
        FILE *fp;
    
        struct sockaddr_in clientaddr, serveraddr;
        char buf_in[PACKET_SIZE];
        char buf_out[PACKET_SIZE];
        char *par_buf;
    
        // 소켓연결을 만든다.
        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        bzero(&serveraddr, sizeof(serveraddr));
    
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
        serveraddr.sin_port = htons(12345);
    
        if(bind (server_sockfd, (SA *)&serveraddr, sizeof(serveraddr)) == -1)
        {
            perror("bind error : ");
            exit(0);
        }
    
        if ((state = listen(server_sockfd, 5)) == -1)
        {
            perror("listen error : ");
            exit(0);
        }
    
        while(1)
        {
            clilen = sizeof(clientaddr);
            memset(buf_in, 0x00, PACKET_SIZE);
    
            if ((client_sockfd = accept(server_sockfd, (SA *)&clientaddr, &clilen)) == -1)
            {
                perror("Accept error : ");
                close(client_sockfd);
                continue;
            }
            while(1)
            {
                if ( (n = read(client_sockfd, buf_in, PACKET_SIZE)) <= 0)
                {
                    perror("read error : ");
                    close(client_sockfd);
                    break;
                }
                if ((par_buf = strstr(buf_in, needle)) != NULL)
                {
                    printf("%s", par_buf+2);
                }
    
                memset(buf_in, 0x00, PACKET_SIZE);
            }
        }
    }
    
    이 프로그램은 소켓을 통해서 메모리 상황을 받아서 출력만 해준다.
    받은 문자열을 파싱해서 그럴듯하게 보여주는건 여러분들에게 맡기도록 하겠다.
    프로그램의 실행은 가장먼저 memchecker 을 실행하고 다음 memrecevier 을 실행하고, memsender을 실행하면 된다.