지난주에 inetd 에서  tcpd 를 빌드해서 넣는 부분을 설명 했습니다.

tcp-wrappers_7.6

 를 빌드해 생성된 ibwrap.so , libwrap.so.0 , libwrap.so.0.7.6 라이브러리 들을  /lib 폴더에 복사해 넣습니다.

그리고 tcpd 는 /usr/sbin  폴더에 복사해 주어야 합니다.

만약 inetd 가 없다면 /sbin 에 아래와 같이 busybox 를 링크 걸어 inetd 를 만들어줍니다.

 $ cd /sbin

$ ln -s /bin/busybox inetd

여기 까지해서 /sbin 폴더에 inetd 가 있고, user/sbin 에 tcpd 가 있으며, 저 세가지 라이브러리는 /lib 폴더에 있다고 가정 하겠습니다.


이번시간에는 실제로 간단한 서버와 클라이언트 프로그램을 만들어 서버를 inetd 를 이용해 등록하고

클라이언트에서 요청해 응답이 오는지 확인해 보겠습니다.

먼저 서버 프로그램입니다. 

서버 프로그램은 지난 시간에 설명 했듯이 stand alone 형과 inetd 를 이용한 형태가 있다고 했는데요.

먼저 stand alone 형태의 server 프로그램 소스는 아래와 같습니다.

여기서부터 소스 -------------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


void Error_Handling(char* message);


int main(int argc, char* argv[])

{

    int serv_sock;

    int clnt_sock;


    struct sockaddr_in serv_addr;

    struct sockaddr_in clnt_addr;

    socklen_t clnt_addr_size;


    char message[] = "server test ok!";


    if(argc !=2)

    {

        printf("Usage : %s <port> \n", argv[0]);

        exit(1);

    }


    serv_sock = socket(PF_INET, SOCK_STREAM , 0);

    

    if(serv_sock == -1)

        Error_Handling("socket() error!");


    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family=AF_INET;

    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    serv_addr.sin_port=htons(atoi(argv[1]));

    

    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)

        Error_Handling("bind() error");


    if(listen(serv_sock, 5) == -1)

        Error_Handling("listen() error");


    clnt_addr_size = sizeof(clnt_addr);

    clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);


    if(clnt_sock == -1)

        Error_Handling("accept() error!");


    write(clnt_sock, message, sizeof(message));

    close(clnt_sock);

    close(serv_sock);


    return 0;

}


void Error_Handling(char* message)

{

    fputs(message, stderr);

    fputc('\n', stderr);

    exit(1);

}

 -------------------------------------------------------------------------------------------여기까지 소스

잘 보면 소켓 관련 부분을 직접 처리 하고 있음을 볼 수 있습니다.

하지만. inetd 가 통신 관련 부분을 전담해 주므로 실제 inetd 를 이용한 서버프로그램은 아래와 같습니다.


----------------------------------- inetd 를 이용한 서버 프로그램 소스-----------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


int main(int argc, char **argv)

{

    struct sockaddr *clientaddr; 

    char message[] = "inetd test OK!";

    int  length;


    clientaddr = (struct sockaddr *)malloc(128);

    length = 128;


    if (getpeername(fileno(stdin), clientaddr, &length) < 0)

    {

        perror("socket failure: ");

        exit(0);

    }

write(0, message, sizeof(message));

sleep(1);


    close(0);

    exit(0);

}

--------------------------------------------------------- 여기 까지 ---------------------------

아주 간단해 졌으며 소켓부분이 싹 빠진것을 볼 수 있습니다.

일단 서버프로그램은 arm 용이며, 타겟 보드에서 사용 할 것이므로  arm 용으로 아래와 같이 컴파일 합니다.

 ]#arm-generic-linux-gnueabi-gcc -o inetd_server inetd_server.c 


그리고 클라이언트 프로그램이 필요 합니다.


클라이언트 프로그램 소스 --------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


void error_msg(char* message)

{

    fputs(message, stderr);

    fputc('\n', stderr);

    exit(1);

}


int main(int argc, char** argv)

{

    int sock;

    struct sockaddr_in serv_addr;

    char message[30];

    int str_len;


    if(argc!=3)

    {

        printf("Usage : %s <ip> <port> \n", argv[2]);

        exit(1);

    }

    

    sock = socket(PF_INET, SOCK_STREAM , 0);

    if(sock == -1)

        error_msg("socket() error");


    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);

    serv_addr.sin_port = htons(atoi(argv[2]));

    

    if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)

        error_msg("connect() error!");


    str_len = read(sock, message, sizeof(message)-1);

    if(str_len == -1)

        error_msg("read() error!");

    printf("from inetd_server : %s \n", message);


    close(sock);

    return 0;

}

----------------------------------------- 여기 까지 -----------------------------

리눅스 환경 pc 에서 실행 할 예정이며 아래와 같이 컴파일 합니다.

]#gcc -o client client.c  


딱 보면 알겠지만 클라이언트 에서 ip 와 포트를 주고 접속 하면 서버에서는 걍 "inetd test OK!" 메시지를 보여주는 아주 간단한 프로그램 구조 입니다.


이제 타겟보드에서 저 서버프로그램을 inetd 를 이용해 서비스로 등록하고 실행해서 클라이언트가 접속했을때 메시지가 나오는지 확인할 차례 입니다. 


지금부터 작업은 타겟 보드에서 진행 됩니다.


1. 등록할 프로그램 설치

서버 프로그램(inetd_server)을 /usr/sbin/ 에 옮깁니다.


2.서비스 등록

#vi /etc/services

inetd_server 1392/tcp


3.inetd 환경 설정

#vi /etc/inetd.conf

inetd_server stream tcp nowait root /usr/sbin/tcpd /usr/sbin/inetd_server


4.inetd 프로그램 실행

#/sbin/inetd /etc/inetd.conf


5. inetd 에 등록된 서버 확인

[root@falinux app]$ netstat -a

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       

tcp        0      0 0.0.0.0:inetd_server    0.0.0.0:*               LISTEN 


이렇게 등록된 서버가 LISTEN 상태로 대기중임이 확인 되어야 합니다.


이제 클라이언트를 실행 할 차례 입니다.

미리 컴파일해둔 client 프로그램은 네트워크가 연결된  리눅스 상에서 실행 하면 됩니다.

]#./client 192.168.10.125 1390  

여기서 client 뒤에 붙는 ip 는 서버(타겟보드) ip 이며, 1390 은 접속할 포트 입니다. 당연히 inetd 에 서버 프로그램을 

등록 할때 이부분은 맞춰 주어야 합니다.


결과 

from inetd_server : inetd test OK! 


정상 동작 된것을 확인 하였습니다.