[PREV]
[1]
[NEXT]
|
|
|
Ruby 그리고 AIX
개발이야기 |
2007/03/26 02:17
|
|
|
AIX에서 Ruby 돌리기?
별로 생각하고 싶지 않은 스토리인데.. 상황이 그리 되는 어쩔 수 없으니...
1차시도 1.8.5을 visual age c compiler로 컴팔하기 => __ceil, __floor를 못 찾겠다 꾀꼬리 2차시도 1.8.5를 gcc로 컴팔하기 => 컴팔이 잘 된다 오예~, 그러나 ext/socket 은 왜 컴파일을 안 하는데. 소켓써야하는데 ㅠ.ㅠ 3차시도 1.8.6을 gcc로 컴팔하기 => 오옹 그냥 해봤는데 socket도 들어있네 아싸
흐웅 그나저나 이 머신 왜이리 접속하는데 오래걸려. 그래도 행복하게 ruby를 쓸 수 있네 ㅋㅋ 들어가는게 느리니 느리겠거니...
require 'socket'
t = TCPSocket.new('www.daum.net',80) # 가는 세월 그누구가~ 막을수가 있나요 ㅠ.ㅠ
요게 느린 것도 아마 AIX 요 머신이 특이한 걸 것이야.. 얼래 그런데 ftp로 데이터 받아오기나, 그 외의 것들은 빠른데.... -ㅅ- 알고보니 Ruby에서 ext/socket 모듈로 Socket 생성시 접속이 오라지게 느리게 된다. 꾸에엑 이를 어쩌나.. 소켓이 필요한 부분이 TCPSocket으로 접속도 해야하고, open-uri를 이용해서 ftp에서 파일도 받아와야하는데..
고객은 앞에 있고.. 데모 보여줘야하는데... ㄷㄷㄷ 부랴 부랴 netcat, wget으로 두부분을 스슥 바꿨다. UNIX는 저에게 system, popen과 ``를 주셨나이다. ㄳㄳ
일단 일단락.. 그러나 상황이 조금 바뀌어서 AIX에서 Ruby/Pcap도 써야할 상황. 컴파일을 하는데 잘 안 되네.. -ㅅ- 컴파일하고 나니 모듈 로딩이 안 된다.
구글링하던 도중 AIX에서 Ruby Building할때 1차시도의 해결책을 찾았다. 알고 보니 망할 Visual Age Compiler 6.0의 버그문제. python을 비롯한 다른 오픈프로젝트에서도 관련 얘기가 나오네. -ㅅ- 그래서 vac로 다시 한번 컴팔해봤다.
4차시도 잘 된다. 그러나 확장모듈 로딩이 죄다~ 안 된다. 쩝쩝쩝.. gcc로 다시 회귀 그러면서 아차차 생각난 것... 5차시도 CC="gcc -maix64" 요리 하니 ext/socket에서 지연되던 문제가 사라졌다. 성능도 조금 좋아진 느낌이다. GOOD!
그러나 역시 Ruby/pcap은 로딩이 되지 않는다. (해결되면 포스팅 이어짐 안되면 한동안 좀비모드일듯.. C++ Porting 고고싱 T-T) libpcap 컴파일시에 CC="gcc -maix64" CFLAGS="-g -O2" ./configure --with-pcap=dlpi --disable-ipv6 로 옵션을 줘서 해결. README.aix문서를 읽어보고 bpf를 사용하지 않고 dlpi를 사용하게 하니 문제없이 작동 - 머 특정 용도 활용이라서 원하는 기능만 돌아가는지 확인. (Fixnum을 Symbol로 사용하짐 랄라는 에러가 3개 뜬다 덜덜덜.. -ㅅ-)
추가적인 수정 사항 (흑 2006.03.29 새벽3시 퇴근 ㅠ.ㅠ) 1. Endian 문제가 있어서 (실제 데이터는 리틀엔디안 AIX는 빅엔디안) 2바이트짜리 길이를 나타내는 부분이었는데 len.unpack('s')를 len.reverse.unpack('s')로 수정 2. 이상하게 tcpdump에서 쓴 패킷 캡쳐시간이 리눅스에서와 AIX에서 14시간 정도 차이가 난다. 그냥 그런가 부다 하고 처리하는 중.
오랜만에 AIX만지면서 알게된 잼있는거 linux기반의 opensource들과 AIX가 좀 더 친해졌다. 미리 컴파일된 바이너리를 http://aixpdslib.seas.ucla.edu/ 에서 잘 받아썼는데 IBM에서 rpm으로 공식지원하는 녀석이 생겼다. 이름도 그럴듯하다~ AIX Toolbox for Linux Applications 엄훠 이젠 rpm으로 설치하세요~ 또하나는 netcat, libpcap, tcpdump 그리고 몇몇 소프트웨어를 컴팔하면서 간단하게 에러나는 것을 잡은 부분 정리
1) extern int h_errno; 를 만나면 가뿐히 지워주세요. (AIX버젼 바이너리가 올리간 사이트의 소스와 원본소스를 비교) 2) VAC C 컴파일러는 enum { AA,BB, CC,} 와 같은 코드를 용납하지 않아요~ 마지막에 여유로 쉼표를 찍지 말아주세요~ |
KOEI
2007/03/26 02:17
2007/03/26 02:17
|
|
| 이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/489 |
|
|
|
|
|
libpcap linux에서 timeout 되게 패치하기
개발이야기 |
2007/03/25 20:39
|
|
|
근래에 계속 하고 있는 프로젝트에서 결국 tcpdump를 사용하게 되었는데, Failover 처리를 하다보니 캡쳐하다 특정 시간만큼 패킷이 없을 경우 timeout을 처리해야할 필요성이 생겼다. tcpdump 소스에서 관련 부분을 보면 - tcpdump.c -
885 *ebuf = '\0'; 886 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 887 if (pd == NULL) 4번째 인자가 to_ms, timeout과 관련된 인자로 설정이 되어있어서, 잘 되는구나 하고 진행을 했으나, 리눅스에서는 timeout이 동작하지 않아서 소스를 들여다 봤다. pcap.c에서 보니 죄다 function pointer로 위임해놨군. 으움 실제 빌드를 돌려보고 실제로 컴파일되는 녀석을 찾아보니 이놈이다. pcap-linux.c 그중에 일부를 보면 - pcap-linux.c -
236 pcap_t * 237 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 238 char *ebuf) 239 { ... 267 /* Initialize some components of the pcap structure. */ 268 269 memset(handle, 0, sizeof(*handle)); 270 handle->snapshot = snaplen; 271 handle->md.timeout = to_ms; ... 492 /* Receive a single packet from the kernel */ 493 494 bp = handle->buffer + handle->offset; 495 do { 496 /* 497 * Has "pcap_breakloop()" been called? 498 */ 499 if (handle->break_loop) { 500 /* 501 * Yes - clear the flag that indicates that it 502 * has, and return -2 as an indication that we 503 * were told to break out of the loop. 504 */ 505 handle->break_loop = 0; 506 return -2; 507 } 508 fromlen = sizeof(from); 509 packet_len = recvfrom( 510 handle->fd, bp + offset, 511 handle->bufsize - offset, MSG_TRUNC, 512 (struct sockaddr *) &from, &fromlen); 513 } while (packet_len == -1 && errno == EINTR);
디버거를 돌릴 생각을 못하고 recvfrom 전후로 출력만을 넣어본 결과 blocking이 된다는 사실을 확인. 일단 늘 그렇듯이 당황. nonblocking으로 바꾸면.. 상상하기도 싫고..... 잠시 마음의 여유를 가지고 시간이 별로 없어서 다른 방법을 찾아보지 않고 소스를 고쳐보기로 했다. (얼마전에 했었던 C++로 작업된 프로젝트 삽질 이후에 또 삽질을.... 이번에는 C다. -ㅅ-)
이런 패턴을 어디서 많이 보던건데..... 아하! IRC서버소스에서 sleep이 없을 때 select를 쓴다.. 이건 상관없잖아!! ACE에서 recv에서 timeout을 지원하지 않을 때 어떻게 하더라. multiplexer의 timeout을 이용하면. That's right~ 그래서 붙이려다가 이왕이면 select말고 다른거 한번 써보자. 해서 epoll로 살포시 붙여봤다. 작업하면서 소스보기 번거로우니 쓰지 않는 파일이나 화면에 출력결과를 보여주는 루틴등은 싸악 날려주고 -ㅅ- 오옹 보다보니 리눅스에서 어떻게 캡쳐를 하면 되는지도 나온다. 여러 인터페이스(각각 fd로 나오니까)에서 캡쳐하는걸 하나의 epoll로 처리해도 괜찮겠다는 생각이 들기 시작.. 그러나 그런게 중요한건 아니니..
#include <sys/epoll.h>
.... 중략 ....
#define EPOLL_EVENTS_COUNT 16 static int epollfd = -1; static struct epoll_event ev, * epoll_events = NULL;
.... 중략 ....
pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms char *ebuf) { .... 중략 ....
handle->selectable_fd = handle->fd; do { if ( -1 == epollfd) epollfd = epoll_create(EPOLL_EVENTS); if ( -1 == epollfd ) break; if ( NULL == epoll_events ) epoll_events = (struct epoll_event *)malloc(sizeof(*epoll_events) * EPOLL_EVENTS); ev.events = EPOLLIN; ev.data.fd = handle->selectable_fd; if ( -1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, handle->selectable_fd, &ev) ) break;
handle->read_op = pcap_read_linux; handle->inject_op = pcap_inject_linux; handle->setfilter_op = pcap_setfilter_linux; handle->setdirection_op = pcap_setdirection_linux; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = pcap_stats_linux; handle->close_op = pcap_close_linux;
return handle; } while(0); fprintf(stderr, "epoll setting error\n"); pcap_close_linux(handle); free(handle); return NULL; } .... static int pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) { u_char *bp; int offset; #ifdef HAVE_PF_PACKET_SOCKETS struct sockaddr_ll from; struct sll_header *hdrp; #else struct sockaddr from; #endif socklen_t fromlen; int packet_len, caplen; struct pcap_pkthdr pcap_header;
int n ; /* epoll returned count */ .... 중략 ....
/* Receive a single packet from the kernel */
bp = handle->buffer + handle->offset; do { /* * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return -2 as an indication that we * were told to break out of the loop. */ handle->break_loop = 0; return -2; } fromlen = sizeof(from);
n = epoll_wait(epollfd, epoll_events, EPOLL_EVENTS, handle->md.timeout); if (0 >= n) { break ; } for ( int i = 0 ; i < n ; ++i ) { if ( epoll_events[i] == handle->selectable_fd ) {
packet_len = recvfrom( handle->fd, bp + offset, handle->bufsize - offset, MSG_TRUNC, (struct sockaddr *) &from, &fromlen); } } while (packet_len == -1 && errno == EINTR);
if ( n == 0 || ( n < 0 && errno == EINTR ) ) { /* callback function must check packet_header, buffer_pointer is NULL. if they are NULL, it is timeout */ callback(userdata, NULL, NULL); return 0; }
.... 중략 ....
static void pcap_close_linux( pcap_t *handle ) { struct pcap *p, *prevp; struct ifreq ifr;
.... 중략 ....
if (handle->md.device != NULL) free(handle->md.device); handle->md.device = NULL; if (handle->selectable_fd > 0 ) /* 여긴 대충 대충 -ㅅ- */ { close(epollfd); } pcap_close_common(handle); 요렇게 간단하게 몇 부분을 고치니 timeout을 callback에서 packet_header와 capture buffer가 NULL임을 확인하는 것으로 timeout 체킹이 가능해졌다. 다만 50라인 정도 작업하는데 3시간 정도를 쓰다니 -_+ 요튼 소기의 목적을 달성하고 timeout을 이용한 다른 코드를 tcpdump에 붙이기 성공. 작업하면서 뻘짓한 것은 tcpdump 소스를 보면서 print-*.c 얘네들을 지우면서 소스를 파악할 때까지는 분위기가 좋았다. libpcap 소스를 보면서 먼저 문서화된 것을 보지 않아서 인터페이스를 파악하는데 삽질한 것(Ruby/Pcap만으로 이미 난 대부분을 알고 있어라는 자만심에)에서 시간을 많이 뺏겼다. 언제나 그렇듯이 소스보다는 문서를, 문서보다는 예제를 먼저 보자라는 생각을 빼먹는다. 작업하면서 printf에서 사용하는 formatted string에서 잼있는 것을 발견. (나만 몰랐는지도)
sprintf(buffer, "%s%0*d", orig_name, max_chars, cnt);
%*d라고 적으면 두개의 인자를 받고 앞의 인자가 *로 자리수를 받고 뒤의 인자가 값이 된다.
여튼 즐거운 working sunday..... ㅠ.ㅠ
|
KOEI
2007/03/25 20:39
2007/03/25 20:39
|
|
| 이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/488 |
|
|
|
|
|
사랑하는 조카 =)
사랑하는사람들 |
2007/03/23 00:57
|
|
|
|
우리집 귀염둥이 나연이 =) 이제 조금 있으면 만으로 두살이 된다. 작년 여름이었던거로 기억하는데, 지금이랑 비교해보면 무지 무지 통통했던 시절.. 개인적으로는 이 사진이 가장 맘에 든다. 주말에 놀러왔다가 가고나면 언제 또 오나 하는 생각이.. :'( 보고 싶다~ |
KOEI
2007/03/23 00:57
2007/03/23 00:57
|
|
| 이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/487 |
|
|
|
|
|
[리뷰] Ubuntu Feisty - 충분히 성숙한 데스크탑 환경
전산쟁이 맹달이 |
2007/03/20 12:50
|
|
|
한줄 요약: 더이상 인터넷 전자거래, 게임을 제외하면 더이상 윈도우를 쓸 일이 없겠다.
feisty에서 놀랜 점 1. 동영상 재생시 곰플레이어가 안 부럽다. totem으로 동영상 재생시 코덱이 없으면 코덱 패키지를 깔으라는 창이 뜬다.
2. 콘솔에서 명령어가 없을 때 요런 메시지가 나온다. koeikim@koeikim-note:~/Project$ svn The program 'svn' is currently not installed. You can install it by typing: sudo apt-get install subversion bash: svn: command not found
엄훠 패키지가 없으니 친절하게 요거로 까세요 라는 설명을 command-not-found, command-not-found-data 패키지를 참조하시라.
3. 각종 하드웨어 회사에서 만든 제한된 드라이버 설치시(그래픽, 랜카드 특히) 예전에는 따로 컴파일을 하고 깔았던 것을 restricted라고 묶은 패키지를 기본 제공하고, 설정을 직접했어야했다. 지금은 시스템->관리->Restricted Driver Manager 가 생겼다. Enable만 하시라.
4. 무선 인터넷 연결 edgy까지는 설정을 지원했으나 가용가능한 무선 인터넷 자원을 알아보기 힘들었고, 네트웍을 다시 잡는 부분이 제대로 동작하지 않았다. 지금은 무선 인터넷 클릭시 사용가능한 무선네트워크 목록이 나오고 선택이 가능하다.
아직 안정버젼이 아닐테니 가지는 애로사항들이 없을리가 없겠지. 1. 처음에는 영문으로 까시라. 한글로 했을 경우 영문 키보드를 잡아도 에러가 뜨시더라 -ㅅ- 2. 네트웍이 연결되지 않았을 경우 패키지를 못 받아온다. 특히 Restricted Device Manager는 쪼금의 애로사항이 있으니 꼭 네트웍을 잡고 까시라~
|
KOEI
2007/03/20 12:50
2007/03/20 12:50
|
|
| 이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/486 |
|
|
|
|
|
근래에 하는 프로젝트를 통해 배운 것들 몇가지
개발이야기 |
2007/03/17 14:09
|
|
|
요사이 개발자로써의 목표는 "새로운 것을 접할 때 빠른 결과와 좋은 성능을 보장하는 개발하기"였다. 실제 여러가지 실제적인 상황을 보다보면 대부분 아는 것보다 모르는 것이 많은 것이 당연한데, 늘 그러한 일을 할 때면 밑바닥부터 모든 것을 만들겠다는 아집에 많은 시간을 쓰는 경우가 많았다. (알고보면 모든 것을 밑바닥부터 만들는 경우는 없는 것과 마찬가지이다.)
해야할 일은 TCP로 돌아다니는 패킷을 캡쳐 => 캡쳐된 패킷을 스트림으로 전환 => 특정 프로토콜에 맞게 파싱
장님 코끼리 만지기 식으로 도입한 프로세스 1. 고객에게 정보 수집 2. 먼저 빠르게 사용할 수 있는 라이브러리를 찾기.(libpcap) 3. lightweight framework language( Ruby, Python과 같은 유연하고 제네릭한 언어)에서 해당 라이브러리 찾기 (pcapy, Pcap/Ruby) 그중 Pcap/Ruby에서 아주 쓰기 편하고 이쁜 라이브러리를 기반으로 구현을 해서 나머지 기능을 모두 기 능 구현을 했었다. 4. 그 외에 세부적으로 필요한 기능상의 내용은 TCP가 어떻게 돌아가는지는 오픈소스 구현물 tcpflow, wireshare, 그리고 관련 자료 wikipedia, the TCP Guide를 참조해서 Ruby로 만든 프로그램에 적용하는 식으로 개발을 했었다.
3주 정도의 기간에 결과물을 대략 산출해내는데 성공했으나 - 아직 진행중 - , 몇 가지 문제점 및 개선방안을 발견할 수 있었다. 결국 실용주의 프로그래머에서 본 내용을 다시 한번 뼈저리게 느끼게 된다.
수행하면서 좋았던 점 1. 1주일 이터레이션 : 피곤하고 많은 시간을 뺏긴다고 생각했으나, 가야할 방향을 알려주는 나침반 역할을 수행했다. 2. Lightweight framework language 활용 : ruby,python과 같은 유연하고 쉬운 언어를 통한 접근은 새로운 기능을 사용하는데 있어서 지렛대 역할을 수행했다. 또한 어떤 부분이 성능이 필요한지, 아닌지에 따라서 사용 여부를 판단할 수 있었다.
개선해야할 점 및 반성점 1. 기존에 있던 구현물을 최대한 활용하기(Unix 철학처럼 simple is best를 최대한 활용하라.) 기능을 구현하는데 있어서 라이브러리보다 더 좋은 수단은 이미 구현된 프로그램이다. 그것을 최대한 재활용할 수 있는 방법을 먼저 강구했었으면 더 빠르게 그리고 안정적으로 구현이 가능했을 것이다. tcpdump를 이용해서 파일을 주기별로 만든 다음에 그걸 파싱하는 프로그램을 작성한다던지 하는 등의 개발방법론을 적용했다면 더 빠르게 개발이 가능했었을 것이다. 2. 고객 그리고 같이 일하는 사람들의 얘기를 좀 더 주의깊게 들으라. 해당 문제를 좀 더 쉽게 단순화시킬 가능성이 높아진다. 받은 데이터를 기존에 같이 일할 때처럼 csv파일과 같은 형태로 만들기 위해 모두 파싱을 하느라 3-4일 정도의 기간을 소요했는데, 오프셋으로도 처리가 가능했었다. 기존에 같이 일할 때 방법만을 생각하고 개발하느라 그러한 문제점이 발생했었는데 생각해보니 지나가는 말로 이 안건을 개발하면서 관련 얘기를 들었던거 같다. 3. 그중에서도 실시간성을 어떻게 감안하느냐에 따라서 concurrent 모델 혹은 배치작업(분리된 프로세스)로 처리하는 것이 월등히 좋은 성능을 발휘할 수 있다. 실시간의 DB 트랜젝션 그리고 실시간의 raw data를 파싱하는 작업등은 시간에 민감한 다른 작업에 지대한 영향을 줄 수 있다. 다량의 로그데이터를 처리하거나 실시간성이 중요한 패킷캡쳐등을 할 때 작업을 분리해 배치처리를 하는 방향으로 모델을 작성했었어도 나쁘지 않은거 같다.
프로세스 수정안 1. 고객에게 여러가지 제반사항에 관한 정보를 수집하기. 2. 같이 개발할 사람들과 협업할 부분에 대한 정보를 얻기 3. 모델을 쉽게 재구성하기 4. 해당 기능과 같은 혹은 비슷한 프로그램을 찾기 5. 실행해보기(기능, 성능체크) 6. 역할에 맞게 최소한의 수정 (라이센스 정책을 어기지 않게 모델을 구성하는데 참조) 7. 그 외의 부분은 상황에 따라 lightweight framework language와 기존의 언어로 빠르게 구현
|
KOEI
2007/03/17 14:09
2007/03/17 14:09
|
|
| 이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/485 |
|
|
|
|
«
2007/03
»
| 일 |
월 |
화 |
수 |
목 |
금 |
토 |
| |
|
|
|
1 |
2 |
3 |
| 4 |
5 |
6 |
7 |
8 |
9 |
10 |
| 11 |
12 |
13 |
14 |
15 |
16 |
17 |
| 18 |
19 |
20 |
21 |
22 |
23 |
24 |
| 25 |
26 |
27 |
28 |
29 |
30 |
31 |
|
|
Total : 23773
Today : 6
Yesterday : 6 |
|
|