강좌 & 팁
지난주에 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!
정상 동작 된것을 확인 하였습니다.