기분이 복잡하면 무제 노트를 펴고, 그냥 머리속의 이런 저런 생각들을 마음에 드는 펜으로 끄적여보곤 한다. 이래저래 편하게 적다보면 딱히 정리되는 것은 없더라도, 무언가 편해지는 느낌이 있어. 

오래간만에 내 블로그에 들렀다. 주인조차 들르지 않는 블로그라니, 누가 와서 들러보겠는가. 마지막 포스트가 구글코드잼 예선 통과에 관한 것이었구나. 결과를 안적었었네. 결과는 사실 창피하다. 

http://www.go-hero.net/jam/10/name/hatemogi

본선1라운드의 A, B, C중 한번이라도 1,000위 안에 들면 본선2라운드로 진출하는 것이었는데, 세번 모두 1,800위 정도의 저조한 성적을 기록하며 탈락했다. A, B, C 모두 참가하고도 (즉, 7시간 30분을 들이고도) 다 떨어지는 최악의 시나리오가 펼쳐졌달까? 세 번 모두 가장 쉬운문제만 풀 수 있었다. 나머지는 이해도 못한 문제가 많았다.  

아무튼 저렇게 떨어지고나니, 허탈감이라해야할지 뭐랄지 모를 묘한 부정적 감정에 휩싸여버렸다. 첫 도전에 쉽지 않을거라 생각은 했지만, 그래도 본선2라운드는 진출 할 수 있을거라 내심 기대했었는데 말이다. 

대학때, 자료구조 수업을 들었을 때의 느낌이랄까? 첫 전공수업다운 전공수업이었는데, 쉽게 적응하지 못했을 때의 당혹감과 비슷하다. 내가 좀 한다고 자만하던 분야에서의 코깨짐? ㅋ

따지고보면 뭐 세계 4,000위쯤 되니, 그렇게 형편없는 것은 아니라고 위안해보지만, 난 이해할 수도 없는 문제들을 10~20분에 다 풀어내는 애들이 있다는 사실을 보면 주눅이 드는 기분은 피할 수 없다. 

내년에 또 도전해 봐야지 뭐. 그냥 무작정 재도전이 아니라, 알고리즘 책이라도 한권 공부하면서 준비하자구.

Posted by hatemogi 트랙백 0 : 댓글 3

Google Code Jam 2010 QR통과

2010.05.10 19:35 from 일상
얼마전 우연히 발견한 Google Code Jam, 살펴보니 올해로 3년째인 코딩 실력 뽐내기 대회인 것 같았다. 오래전 학창시절 이런 경진대회(?)에 나갔어야 했겠지만, 학교다닐 때는 노느라 바빠서, 나갈 생각도 못했지. 게다가 어설픈 기억엔 단체참가 위주였던것 같은데, 이 대회는 단독 참가인것 같더군. 

녹슬은 머리에 기름칠해야겠다는 심정으로 일단 참가신청을 하고, 과거 기출문제를 연습삼아 풀어보기로 했다. 예선 문제야 너무 쉬웠지만, 본선 1라운드 부터 쉽게 풀리지 않는다. 첫번째 문제를 풀었으나, large-set에 대해 답이 통 나오질 않아, 결국 루비만으로 푸는 것은 포기하고, C extension 넣어서 처리. 보통은 C++로 많이 푸는것 같아 보인다. 재미없는 구현으로 한참 시간을 쏟고 나니, 흥미가 급격히 떨어졌고, 별다른 공부나 연습없이, 예선날짜는 다가왔다. 

우리나라 시간으로 5월 8일 오전8시. 토요일인 점은 좋았지만, 오전 8시는 내게 너무 힘든시간 아닌가? 어렵사리 일어나서 눈비비적 거리며 문제를 읽기 시작. 24시간 내에 풀면 되지만, 난 오후에 약속이 있으므로, 오전내에만 다 풀자는 생각으로 시작했다. 그런데 이게 왠걸? 작년 예선문제에 비해 난이도가 꽤 높은걸? 풀다가 딴짓하다, 밥먹다가, 좀 누워있다가, 쉬엄쉬엄 했다지만, 총 소요시간은 무려 6시간. 구글 왈, 한시간 남짓에 풀 수 있을것으로 보인다고 했었는데 말이다. 

세번째 문제의 large set을 처리하지 못해서, 76점으로 마무리했고, 예선은 통과한 셈. 풀지 못했던 세번째 문제의 large set도 오늘에야 재도전해서 풀기야 했지만, 두시간 이상 걸린것 같다. 

다음주 토요일의 본선 1라운드에서는, 이보다 높은 난이도의 문제들을 2시간 30분 내에 풀어야 한다. 목표는 본선2라운드까지 진출하는 것인데, 빠듯해 보이는구나. 

다른사람들의 결과를 보니, 참 대단들 하다는 생각이 든다. 갖가지 언어로 푸는 사람들도 있고말이다. 일단의 생각은 진출할 수 있는 수준까지 나가고, 내년에도 기회되면 참가해봐야겠다는 생각이 든다. 두뇌 운동 삼아 말이다. 

http://code.google.com/codejam/contest/scoreboard?c=433101#vf=1&sp=1641
Posted by hatemogi 트랙백 0 : 댓글 4

TLS on iPhone

2010.03.24 17:22 from programming
아이폰 응용프로그램으로부터 서버와 네트워크 통신하는 내용을 암호화 하기 위해 TLS(Transport Layer Security)를 쓰는 방법을 정리합니다. 

HTTPS

HTTP통신의 경우에는 NSURLRequest를 사용할때 https 스킴을 사용하면 자체적으로 HTTPS를 사용하므로, 별다른 설정 없이 보안설정이 가능합니다. 일반 HTTP통신과 동일한 방식으로 NSURLConnection 객체를 활용하여 HTTPS를 사용할 수 있습니다.

서버측에서 비공인 인증서(eg. self-signed certificate)를 경우에는, 아래의 delegate method를 구현해서 처리 가능합니다.

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

TLS socket

하지만, HTTP통신이 아닌, 일반 소켓 통신의 경우 얘기가 조금 다릅니다. NSStream 객체로 만들어 소켓통신을 할 수 있습니다만, SSL통신을 하기위한 옵션이 있습니다. NSStream을 만들고 스트림을 open하기 전에 아래의 속성을 설정하고 나서, 스트림을 열면, 열리자 마자 TLS handshaking을 진행합니다. 

[stream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

하지만, 이경우에 비공인 인증서는 사용할 수 없습니다. 어떻게 하면 비공인 서버인증서로 TLS통신을 할 수 있을까 조금 더 자료를 찾아본 결과, CoreFoundation쪽을 직접 건드리는 방법이 있었습니다. CFReadStream과 CFWriteStream에 속성을 설정할 수 있는 함수가 있고, 아래의 코드처럼 kCFStreamSSLValidatesCertificateChain속성을 NO로 설정해서, 서버인증서 검증과정을 생략할 수 있습니다.

NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
 [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
  kCFStreamSocketSecurityLevelTLSv1, kCFStreamSSLLevel,
 nil];
CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);

위의 설정후에 CFReadStream과 CFWriteStream을 각각 NSInputStream과 NSOutputStream으로 바꾸어 사용하면, open후 TLS handshaking이 진행된 채로 데이터를 주고 받을 수 있습니다.

 
Posted by hatemogi 트랙백 0 : 댓글 0
EventMachine

EventMachine은 Ruby, Java, 그리고 C++을 위한 고성능 네트웍 I/O라이브러리이다. 최근 네트웍서버를 하나 만들게 되었는데, 프로토타입 개발과 성능테스트 모듈을 EventMachine으로 개발했다. 예전에는 Ruby용 라이브러리라고만 생각했는데, 살펴보니 Java나 C++환경에서도 쓸 수 있을뿐더러 (JRuby가 아니고서야 누가 쓸까 궁금하긴 하지만 말이다) 보면 볼 수록 잘만들었다는 생각이 들었다.

실제 서버는 사내의 자체개발 프레임워크를 이용해 C로 개발을 완료하고 성능테스트를 돌리려는 시점이었다.  EventMachine을 써서 개발한 루비 프로세스를 17대의 서버에 얹어놓고, 한꺼번에 접속해서 부하를 주려는데, 각각의 루비프로세스가 TCP커넥션이 1024개 근처가 되면 죽어나가는 상황 발생. 당연이 Max Open File Descriptor문제이리라 생각하고, 17대의 서버에서  ulimit을 모두 올려주었다. soft/hard limit을 모두 올려놓고 다시 테스트를 하는데, 또다시 1024개 근처에서 루비프로세스는 죽고 말았다. 

성능테스트 모듈자체가 중요한 상황이 아니었기때문에, 해당 문제를 해결하는 일은 접어두고, 성능테스트 자체에 집중하기로 했다. 결국 각각의 서버에서 다수의 루비프로세스를 실행해서 목표서버에 무식하게 많은 커넥션을 열고 트래픽을 걸어서 테스트를 완료했다. 

Ruby의 select문제

그러고 며칠 후, 아무리 생각해도, 루비 프로세스가 죽어나간 점이 찜찜해서, 여유시간에 해당 문제를 파고들었다. 찾아낸 결과 자료는 의외로 가까운 곳에 있었다. eventmachine패키지안에 포함된 EPOLL이라는 텍스트 문서에 아주 자세하게 설명되어있던 것. 

select함수는 해당되는 descriptor가 수백개가 넘어가면 성능저하가 매우 진다고 하는데, 게다가 루비에서는 select를 사용할 수 있는 디스크립터 수가 1024개로 제한되어있던 것. 우선 루비에서 하드코딩으로 이 숫자가 제한되어 있는 점은 그러려니 한다. 어차피 수백개 넘어가면 지나친 성능 저하로 실용성이 매우 적기 때문에 1024개도 너무 많다고 생각하니까 말이다. 하지만, 문제는, 믿었던 EventMachine인데, 난 이 친구가 당연히 epoll/kqueue를 기본으로 사용한다고 믿어 의심치 않았던 것.  


epoll, kqueue

EventMachine의 기본값은 그냥 일반 select함수를 사용하는 것이었다. 응? 설치할 때 컴파일하면서 시스템별로 사용할 수 있는 함수 사용하는 거 아니었어? 당연히 내 Mac에서는 kqueue를 쓰고, Linux환경에서는 epoll써줘야하는 거 아니야? 결과적으로, 현재버전까지(0.12.10) 아직은 아니었다. 

EM.run 블럭을 실행하기전에 

EM.epoll
EM.kqueue
EM.run {
   ...
}

를 실행해 주어야, 해당 기능을 쓸 수 있는 환경에서 작동을 하며, 그렇지 않다면 그냥 select를 쓰게 되는 것.  두 함수는 해당 기능을 쓸 수 없는 환경에서는 무시되므로 환경 생각하지 않고 호출해주어도 되겠다. 기본값이 일반 select를 쓰게해놓은 이유는 뭘까? 

아무튼, EventMachine을 쓰면서 다수의 연결을 유지해야할 필요가 있다면, 위 메소드들을 꼭 호출해 놓고 사용해야할듯 하다.  




Posted by hatemogi 트랙백 0 : 댓글 1

드리프트 제어 유닛

2009.08.24 11:56 from programming
장난감 R/C카 제어

최근 몰입하고있는 개인 프로젝트가 있습니다. "소프트웨어 개발자의 하드웨어 개발기"를 쓰게 된 이유이자, 목표 결과물은 오래전의 꿈과 관계되어 있습니다. 사실 대학시절에 완성했어야할 프로젝트인데 10여년이 지난 이제서야하고 있네요. 어린시절 꿈쫓기의 하나입니다.

만들고 있는 것은 맥북(or 아이팟 터치)로 R/C 자동차를 제어하는 시스템입니다. 이 프로젝트를 핑계로, 입문용 R/C 자동차 세트도 하나 샀습니다. 어릴적에 그토록 갖고 싶었던 장난감이죠. (사실은 이게 사고싶어서 이런저런 핑계를 만든건지도 모릅니다)

DSC_6174

임베디드 시스템을 만들어 넣어서, MacBook이나 iPod Touch에 개발해 넣은 소프트웨어로 저 사진의 장난감 차량을 제어하는 것입니다. 

컴퓨터 -> 무선 통신 -> 임베디드 시스템 -> R/C 자동차

이런 제어 흐름인데요, 사실 임베디드 시스템이 가장 약한부분이자, 관심부분입니다. 이번 기회를 통해서 어느정도 경험이 쌓이면, 여기에 간단한 OS를 얹는다거나, 루비같은 언어의 인터프리터를 얹는다거나해서 더 어릴쩍의 꿈을 이뤄볼 수도 있겠다는 야망이 불타 오릅니다. 흐흐, 김칫국물 마구 마시고 있습니다.


학창시절에 했어야할...

사실 이 구성은 대학시절에 구현했던 내용의 연장선 위에 있습니다. 초기 모델은 대학 신입생 시절에 전시회에 출품한 프로그램이었습니다. 당시에는 정말 애들용 R/C를 PC의 패러럴 포트에 연결한 회로를 이용해서 제어했었지요. 단순히 키보드로 R/C카를 제어한 간단한 예제였습니다만, 관람객(?)들은 키보드를 눌렀는데 실제 장난감이 움직인다며 신기해해서 반응이 좋았습니다. 

이어서, 제대로된 R/C 차량을 이용해서, 차량동역학 시뮬레이션을 해보고 싶었습니다만, 각종 미적분 수학식의 무게에 압도당해 완성하지 못했던 아쉬움이 남아있습니다. 다시 한번 기회를 잡아 인공지능 수업때에 과제프로젝트로 구현하려 했었으나, 프로젝트 상담중에 교수님과의 상담중에 방향이 바뀌어 결국 남들 다하는 시시한 오목 프로그램 만들었었습니다. 결국 그렇게 시간은 가고, 그냥 졸업해버렸네요.

당시에는 자동차 시뮬레이션 게임도 지금보다는 사실성(?)이 떨어지던 시점이었기 때문에, 계속 파고들었으면, 그럴싸한 자동차 시뮬레이션 소프트웨어를 흉내내볼 수 있었을지도 모르겠습니다만, 지금은 아무리 잘만들어봐도, 요새의 레이싱 게임만큼 만들기는 절대 무리겠지요. 대신에 공개된 레이싱 게임엔진을 찾아다 활용해 볼 수도 있겠네요. 

어쨌건, 차량제어 시뮬레이션을 저 1/10 스케일의 폭스바겐으로 보여줄 수 있다는 가정하에, 이런저런 프로그램을 만들어 볼 수 있겠습니다. 


드리프트 놀이

사진의 저 차량은 온로드(포장도로) 주행용 4륜구동 차량인데, 타이어를 드리프트용으로 교체해서 달았습니다. 액션영화에서 빠지지 않는 자동차 추격신의 하일라이트는 차량간 총격씬과, 골목길에서의 드리프트씬 아닐까요? 주인공의 차량은 아찔하게 사고를 피해가며, 골목길을 빠져나와 큰길로 접어들며 요란한 타이어 마찰음과 함께 카운터 스티어링과 함께 드리프트를 선보이죠. 

아래 사진은 실제 드리프트 경주용 차량의 사진입니다.




드리프트 관련 자료를 찾아보다가, 드리프트의 원리와 방법들을 살펴보게 됐는데, 역시 드리프트가 쉬운게 아니더군요. 덕분에 왜 가능 방향과 반대로 카운터스티어링을 걸어주는지도 알게됐습니다. 

드리프트의 기본은 "뒷바퀴의 오버스티어링을 활용해서 차량 주행을 컨트롤"하는 것이더군요. 뒷바퀴의 오버스티어링을 위해서는 차량이 4륜구동이거나 후륜구동이어야합니다. 국내 대부분의 세단차량은 전륜구동이므로, 일반 차량으로 드리프트를 해보기 어렵다는 판단에 이를 수 있습니다. 전륜구동 차량은 오히려 앞바퀴의 언더스티어링 현상이 발생하기 쉽습니다. 

R/C차량의 경우 후륜구동 또는 4륜구동이 대부분인데, 2륜구동 차량으로는 드리프트를 제어하기 어렵기때문에 대부분 4륜구동 차량으로 드리프트 놀이(?)를 한다고 합니다. 4륜구동 차체를 준비해서 타이어만 미끄러지기 쉬운 드리프트 타이어로 교체해도 어느정도의 드리프트는 구사할 수 있습니다.

문제는 이 드리프트 기술을 활용하기 위해서는 뒷바퀴 오버스티어를 만회(?)할 수 있는 카운터스티어링이 적절히 필요하다는 겁니다. (위 사진을 보면 차량은 좌측으로 회전중이지만, 바퀴는 오른쪽을 향하고 있는 것을 볼 수 있습니다. 아래 그림은 반대) 



뒷바퀴가 오버스티어링 되는 상황을 그냥 내버려두면 차체가 계속 스핀이 걸려서 휙 돌아버리게 되는데, 이를 막기 위해, 접지력이 남아있는 앞바퀴의 방향을 회전반대편으로 조절하여, 차체의 회전을 막는 것입니다. 게다가, 속도가 어느정도 줄어서 다시 뒷바퀴의 오버스티어링이 끝나갈 시점에는 다시 카운터스티어링을 풀어줘야, 다시 반대편으로 급회전하게 되는 현상을 막을 수 있습니다. (오락실에서 레이싱 게임할 때, 흔히 겪는 현상이죠. 코너를 돈다고 심하게 핸들을 꺾었다가, 미끌어지기 시작해서 반대로 꺾다보면, 조금 제대로 가는 듯 싶다가 다시 반대쪽 벽을 들이받는 현상이죠)


즉, 적절한 드리프트 코너웍을 위해서는, B시점에 핸들을 반대쪽으로 틀어서 카운터 스티어링을 걸고, D시점에는 정상 스티어링으로 풀어줘야 원하는대로 코너를 빠져나올 수 있는 것입니다.


드리프트 컨트롤 유닛

이 기술을 구사하려면 많은 연습이 필요한것 같습니다. 순간적인 반응도 중요할테구요. 여기서 만들 임베디드 시스템의 응용 방법이 떠올랐습니다. 임베디드 시스템은 현재의 바퀴 회전각과 전후진 추진력을 알고 있으니, 현 차체의 움직임을 판단할 수 있다면 (즉, 오버스티어링 현상을 감지할 수 있다면) 자동으로 카운터스티어링을 걸어줄 수 있을거라는 생각이 들었습니다. 즉, 스핀현상을 막아서, 대충의 손기술로도 드리프트 놀이를 해볼 수 있지않을까 합니다. 다시말하면, 실제 차량에 탑재되는 차량 주행안전시스템(ESC등으로 불리는 옵션들)의 한 보기를 구현해볼 수 있다는 겁니다. (이거 찾아보다가 ABS의 원리까지 파악하게 됐습니다.)

더 흥미로웠던 점은, 이렇게 구현하려는 시스템이, 실제 R/C계에 상용화된 상품이 있다는 점이었습니다. 아래는 해당 제품을 판매하는 HPI사의 홍보 동영상입니다. 각각 해당기능을 켰을때와 껐을때의 시범 동영상이 있습니다. 물론 홍보용이니까 조금 과장된 면은 없지 않겠습니다만, 적절한 자동 카운터스티어링으로 스핀을 막아 안정된 드리프트 주행을 보여줍니다.   



제품의 연결선을 보아하니, 가속도 센서 값을 읽어 순간적인 회전이 발생하면 오버스티어링 상황으로 간주해서 카운터 스티어링을 걸어주는 방식으로 구현한것 같습니다. 간단하게는 이정도로 드리프트를 돕는 유닛을 만들 수 있겠구요, 나아가서는 가속/감속 상황까지 판단해서 더 나은 수준으로 구현해 볼 수도 있을 것 같습니다. 

그 외의 재미난 응용사례도 있으면 좋겠습니다. 이 결과물은, 10월달에 열리는 회사 개발자 컨퍼런스에 출품할 예정입니다.

====================================
인용자료: hpiracing.com, drivingfast.net

Posted by hatemogi 트랙백 0 : 댓글 8

티스토리 툴바