구글 두들에 나온 Hedy Lamarr 글을 읽고

며칠 전 구글 두들 (2015-11-09) 로 Hedy Lamarrs 라는 배우, 발명가인 여성에 대한 글을 읽었다. 트위터에 올라오는 것들 보다가 예전에 전공 과목 배울 때 내용이랑 섞여있는 게 있길레 간단히 정리.

흔히 약어로 쓰는 SS (spread spectrum), DS (direct sequence), FH (frequency hopping) 같은 걸 쓰고 있으니 참고해서 읽어주시길.

Hedy Lamarrs 와 FH

위키백과 항목에 따르면

Lamarr and Antheil realized that radio-controlled torpedoes, while important in the naval war, could easily be jammed, which caused the torpedo to go off course. With the knowledge she had gained about torpedoes from her first husband, and using a method similar to the way piano rolls work, they designed a frequency-hopping system that would continually change the radio signals sent to the torpedo.

즉, Lamarr 와 공동 발명자가 고안해 낸 것은 일종의 FHSS 시스템. Spread spectrum 방식 자체가 a. 전체 대역을 다 관찰하지 않고는 노이즈 플로어만 상승시키는 걸로 보이고 b. 특정 (좁은) 대역의 재밍으로는 통신을 재밍하기 어려운 장점 떄문에 풀려던 문제 (어뢰의 유도 신호를 재밍당하지 않게 하는 것) 에 적합하다는 것.

Wireless LAN, …

현재 사용하고 있는 무선랜 표준 (WLAN; 802.11) 과 발명 사이에 관계 있다는 설명글들이 쭉 올라오는데, 아주 거칠게 말하면 큰 관련은 없다 — 작게는 있다(?). 무선랜 대역인 2.4 GHz (다른 대역도 있지만) 에는 전자레인지가 동작 중인 경우 엄청난 양의 노이즈가 생기기 때문에 이를 피하기 위한 방법을 사용한다.

링크한 글에서도 얘기하지만 대부분의 사람이 경험해보지 못한 legacy 802.11 표준을 제외하곤 FHSS는 사용하지 않는다. (대부분의 경우 802.11b, g, n, ac 순서로 경험했으리라)
간단히 정리하자면

  • Legacy 802.11: DSSS or FHSS
  • 802.11a: OFDM
  • 802.11b: DSSS
  • 802.11g, ac: OFDM

그래서 (현재의) 무선랜 기술과 크게 관련있는 건 아니라고 적었던 것.

2G/3G 무선 통신

한국에서 사용하는 2G 무선 기술이 IS-95 인데 (혹은 그 이후의 IS-2000; 3G), 이 기술은 CDMA 를 써서 여러 사용자의 통신을 지원한다. 그리고 이 CMDA가 사용하는 방식이 DSSS.

GPS?

이건 왜지. P코드 때문이라고 하기엔 너무 먼데 (…….)

Bluetooth

이게 왜 안나왔는지는 정말 모르겠지만. Bluetooth 통신은 FHSS를 쓴다. 차라리 직접적으로 연관관계가 있는 이쪽을 위주로 정리해줬어도 좋았을지도.

음 그렇지만 FHSS도 spread-spectrum 자체가 맞기도하고, 넓은 대역에 pseudo-random number sequence를 써서 특정 형태의 재밍을 피할 수 있는 무선 통신 방식…을 생각하면 뭐 죄다 적용될 수는 있을지도?

nginx + ngx_pagespeed

꽤나 예전에 동아리 서버에는 적용해봤는데 — 동아리 서버는 apache 웹서버를 써서 구글에서 바이너리로 배포하는 mod_pagespeed 를 썼지만 — 이 블로그가 쓰는 웹 서버는 nginx를 써서 적용 못하고 있었다.
Nginx 는 다 좋은데 동적으로 로드 가능한 모듈을 지원하질 않아서 소스에 넣고 빌드해줘야하는 것. 개인 웹 서버라 개발툴 없이 돌리는 상태를 유지하고 싶어서 회사 개발머신을 빌려 데비안 패키지만 만들고 옮겨서 설치하는 것으로. 아래는 그 기록.

빌드 기록

빌드 과정은 소스에서 ngx_pagespeed 빌드하기 를 따라하되 nginx 소스코드와 빌드 자체는 ubuntu 14.04의 debian 빌드 스크립트를 이용했다.

소스 코드 얻기

nginx 소스 패키지와 ngx_pagespeed 소스 타르볼, 그리고 PSOL 타르볼을 얻는다:

# nginx (1.4.6) 소스코드 + 빌드스크립트
$ apt-get source nginx

# ngx_pagespeed 릴리즈 아카이브
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/release-1.9.32.10-beta.zip

# PSOL
$ wget https://dl.google.com/dl/page-speed/psol/1.9.32.10.tar.gz

# 압축 해제 및 필요한 구조로 변경
$ tar -zxf 1.9.32.10.tar.gz
$ unzip release-1.9.32.10-beta.zip

# PSOL 을 ngx_pagespeed 밑으로
$ mv psol/ ngx_pagespeed-release-1.9.32.10-beta/

# ngx_pagespeed 를 모듈 디렉터리로 이전
$ mv ngx_pagespeed-release-1.9.32.10-beta/ nginx-1.4.6/debian/modules/

nginx 빌드룰 수정

데비안 패키지의 빌드룰은 “{패키지-버전}/debian/rules” 에 있다. 여기선 nginx-1.4.6/debian/rules 를 열어 nginx-full 에 해당하는 config.status.full 항의 맨 뒤에 “--add-module=$(MODULESDIR)/ngx_pagespeed-release-1.9.32.10-beta \” 를 추가해서 아래와 같이 수정하다:

config.status.full: config.env.full
  cd $(BUILDDIR_full) && ./configure  \
      $(common_configure_flags) \
      --with-http_addition_module \
      --with-http_dav_module \
      --with-http_geoip_module \
      --with-http_gzip_static_module \
      --with-http_image_filter_module \
      --with-http_spdy_module \
      --with-http_sub_module \
      --with-http_xslt_module \
      --with-mail \
      --with-mail_ssl_module \
      --add-module=$(MODULESDIR)/nginx-auth-pam \
      --add-module=$(MODULESDIR)/nginx-dav-ext-module \
      --add-module=$(MODULESDIR)/nginx-echo \
      --add-module=$(MODULESDIR)/nginx-upstream-fair \
      --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module \
      --add-module=$(MODULESDIR)/ngx_pagespeed-release-1.9.32.10-beta \
            >$@

데비안 패키지 생성

$ cd nginx-1.4.6/
$ debuild -uc -us -rfakeroot -b
$ ls -1 ../*.deb
../nginx_1.4.6-1ubuntu3.3_all.deb
../nginx-common_1.4.6-1ubuntu3.3_all.deb
../nginx-core_1.4.6-1ubuntu3.3_amd64.deb
../nginx-core-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-doc_1.4.6-1ubuntu3.3_all.deb
../nginx-extras_1.4.6-1ubuntu3.3_amd64.deb
../nginx-extras-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-full_1.4.6-1ubuntu3.3_amd64.deb
../nginx-full-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-light_1.4.6-1ubuntu3.3_amd64.deb
../nginx-light-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi-ui_1.4.6-1ubuntu3.3_all.deb

…적당히 기다리고 나면 탑 디렉터리에 .deb 파일 수 개가 생긴다. 위에서 빌드 룰 수정한 nginx-full 패키지를 가져가서 서버에 설치.[1] 빌드 시간을 줄이고 싶다면 debian/control 을 수정하는 것도 (다음 번엔) 고려해야겠다.

설정하기

ngx_pagespeed : Nginx의 PageSpeed 모듈 :: Outsider’s Dev Story 를 참조해서 설정했다. 기본 값 + JavaScript 비동기 로딩 정도 설정함.

총평

Google PageSpeed Insight 점수가 15점 쯤 올랐다 (…). 행복하군 (야)
대신 앞으론 ubuntu 쪽 패키지 업데이트 / Google 쪽 릴리즈 마다 새로 빌드해야한다 (이쪽은 전혀 달갑지 않다…)

PS. (아마도) GPL인 debian/rules 파일을 일부 인용했는데, 이 글 라이센스를 CC-BY 대신 GFDL로 해야하나? 아니면 공정 사용이니 그냥 CC-BY 해도되나?(…)

  1. 빌드할 때 좀 괴롭더라. -j8 주니 빌드 실패한다. 빌드 스크립트에 무슨 삽질을 해놓은걸까? []

지연시간 – 대역폭 곱

학부 데이터 통신 / 네트워크 수업과 대학원 석사 과정동안 배운 많은 개념 중에 내가 가장 감명 깊게(?) 생각했던 부분은 바로 이것,

대역폭 — 지연시간 곱 (bandwidth — delay product)

이게 무슨 의민가?

End-to-end에서 아주 간략하게 생각하자면 하나의 링크에 대해 양쪽 끝 단 사이에 “날아가고 있는” 데이터의 총량이다.[1] 그러니까 둘 사이에 존재하는, 보냈지만 아직 도착하지 않은 데이터의 ‘용량’이란 의미.  이 이상 넣어봐야 실제로 네트워크 위에 있는게 아니라 양쪽 시스템의 버퍼 위 어딘가가 될 것이란 것.
즉, 양 끝 단 사이의 네트워크 자원을 최대한 활용하려면 이 정도의 데이터가 네트워크 위에 계속 존재한단 소리.
지연 시간에 대해 상대적으로 신경을 덜 써도 되는 시스템이라면 약간의 지연 시간을 감수하고라도, 전송량을 극대화 하기 위해서는 이 값 만큼의 데이터가 네트워크로 계속 흐르게 해줘야 한다.

결론적으로, “best-effort” 트래픽을 처리할 때 여러가지 목표를 적당히 trade-off하는게 아니라, 이 것 단 하나만 최적화하면 된다는 것.

이번에 마무리 지은 파일 전송 프로토콜/프로그램에서도 이 개념만 충실히 지키는 형식으로 만들었다.
On-demand로 파일 chunk를 요청하긴 하는데, 특정 크기 — 앞에서 말한 대역폭 — 지연 시간 곱 만큼 — 의 윈도우를 두고, 이 윈도우 만큼의 데이터는 항상 미리 요청하게 한 것.어차피 RTT x 네트워크 대역폭만큼은 미리 요청해야, RTT 후에 요청한 데이터가 NIC를 통해 올라오고, 계속해서 대역폭을 채우게 된다.
실 세계에서도 이걸 최적화 못하면 “굉장히 느린 시스템”처럼 보이게 된다. 총 전송량이 적으면 대역폭 보다 지연 시간이 훨씬 크게 보이기 때문이다. 대역폭이 무한히 커 봐야 데이터는 RTT 후에나 오거든(…). 그래서 광대역 통신으로 해도 RTT가 크면 말짱 꽝.
예를 들어, HTTP같은 프로토콜에서는 한 번에 하나의 요청만 HTTP 연결 위로 오가기 때문에, 충분히 큰 단일 응답을 보내는 경우를 제외하고서는 요청을 보내고 응답을 받는 시간 (= RTT) 동안 이 링크를 채울래야 채울 수가 없다.
그래서 실제로 유저가 느끼는 대역폭이 매우 작다.[2] 덕분에(?) 매우 지연 시간에 예민한 시스템이된다.

그런 의미에서 Google의 HTTP 1.2 SPDY 같은 프로토콜이 나오는 것이기도 하다. 지연 시간이 더 중요하다는 의미로 비슷한 맥락에서 — 이 경우에는 HTTP의 한계가 아니라 TCP slow start의 한계 때문에 — TCP 알고리즘을 수정해서, Slow start의 구현을 사실 상 무시하고, 상대적으로 더 큰 slow-start window를 사용하는 변형(논문도 있다!)을 쓴다.

 

  1. 중간이 몇 hop인지는 중요치 않다 []
  2. 게다가 DNS이름 기준으로 한 호스트에 보내는 연결은 기껏해야 2개. 물론 수 많은 브라우져들이 이걸 어기긴한다 []

곧 Google Chrome Web Store가 열릴 듯 하다

다음은 몇 일전에 받은 메일의 일부. Google Chrome extension을 등록한 사람들을 대상으로 Google에서 보낸 메일이다. 예전에 egloos 밸리에서 특정인(…) 차단하는 확장 기능을 만든 탓인지 나에게도 왔다.

web-app-store

곧 열릴 테니 준비하라 정도? 현재 Chrome이 8.x beta인 상태고, 곧 안정 버전이 공개 될 터이니, 조만간 웹 앱 스토어를 보게 될 듯 하다.

ps. paperinz 의 이 포스팅을 보면 강제로 웹 앱 스토어를 볼 수도 있는 듯…

Breakpad 로 CrashReporter 만들기

최근 한 3주 정도 바쁘더니, 어제 오늘은 좀 여유가 생겨서, 얼마 전에 코드를 읽어 본 google-breakpad를 써서 C++ 코드로 동작하는 바이너리의 crashdump를 특정 서버에 보고하는 간단한 라이브러리(래퍼) + 툴을 작성했다.

내가 이걸 필요로 하는 건, 팀에서 만드는 각종 서버 바이너리를 팀 외부의 여러 곳에서 쓰고 있는데, 이에 대한 덤프를 전달 받는다거나 하는 게 너무 번잡하기 때문 – 실제 라이브 서비스가 되면 다른 얘기지만, 그 전의 개발하고 테스트하는 단계에선 피드백 단위가 너무 크다. 그래서 최대한 빨리 크래시 정보를 얻어내기 위해 간단한 유틸리티를 작성한 것.

일단 본론으로 들어가서, 아주 간단히 breakpad를 소개하자면, Google Chrome처럼, 여러 플랫폼을 지원하는 프로그램을 위한 크래시 덤프를 다루기 위한 툴이다.[1]  Win32 개발자들이 접하는 minidump나, *nix 개발자들이 접하는 coredump를 breakpad 포맷(이라기보단 함수 맵)으로 변경하고, 이를 이용해서 플랫폼이 바뀌어도 같은 형태의 스택 트레이스(stack trace)를 볼 수 있게 해주는 툴이다.

좀 더 세부적으로 보면 다음과 같은 부분으로 되어 있다.

  1. (개별 사용자 용) 크래시가 발생했을 때, 이를 breakpad 에서 사용하는 포맷으로 덤프를 남겨주는 부분: in-process 덤프만 있는 게 아니라, 다른 프로세스에서 dump를 남기는 방식(out-of-process dump)도 지원한다
  2. (Build-System 용) 디버그 정보를 읽어서 breakpad 내부 형식으로 바꾸는 부분 : Win32 pdb 나 –g 옵션을 넣고 빌드한 *nix 바이너리에서 심볼 데이터를 뽑아낸다
  3. (Crash Collector 용) 1에서 나온 정보를 가지고 2를 이용하여 스택 트레이스를 뽑아내는 부분

사실 2, 3 부분은 Windows 환경에서만 프로그래밍 한다면 그다지 중요하지 않다; 어차피 breakpad 도 덤프 자체는 minidump를 쓰고 있고, breakpad 소개의 Build / User / CrashCollector system 다이어그램에 나온 과정도, 디버그 정보가 애초에 분리되어 빌드 되는 환경(/Z7 같은 걸 쓰면 모르겠지만)에선 그다지 더 편해질 건 없다.

그렇지만 1에서 Windows named-pipe를 써서, 크래시가 발생한 프로세스가 아니라, 안전하게 동작 중인 프로세스에서 덤프를 남길 수 있다는 점(Out-of-process 덤프), 그리고 이 덤프 남기는 부분의 코드에서 제공하는 callback 지점들이 적당해서, 이걸 이용해서 간단하게(!) 실제 배치된 시스템의 덤프를 중앙의 서버로 모으는 작업을 간편하게 작성할 수 있었다.

일단 out-of-process로 덤프를 남길 수 있기에, 크래시가 발생한 바이너리에서 할 수 없는 일들 – 메모리 신규 할당, heap 메모리 참조, 기타 등등[2] – 을 맘대로 해도 되기 때문에 웹 서버나 다른 서버로 덤프를 보내는 일이 쉬워진다.

그리하여, 다음과 같은 코드를 짰다. 이 중 다른 서버 바이너리를 작성/배포하는 사람이 신경 써야 하는 건 1에서 노출한 1개의 함수 뿐.

  1. Breakpad의 CrashGenerationClient를 래핑하고, 외부 프로세스에 덤프 처리를 맡기는 부분을 .lib 파일로 분리했다. 이 라이브러리는 초기화 시점에 2를 CreateProcess로 실행한다.
  2. Breakpad의 CrashGenerationServer와 http_upload 부분을 이용해서 crashreport.exe라는 툴을 만들었다.  이 exe는 1에서 크래시가 나면 그 덤프를 만들고, 이 때 호출되는 콜백에서 http로 덤프 파일을 3에게 준다.
  3. 2에서 쓴 breakpad의 http uploader가 HTTP POST(multipart form-data)로 dump 파일을 전송하는 작업을 한다. Python의 BaseHTTPRequestHandler의 do_POST를 override하고, cgi.FieldStorage 를 이용해서 이 dump를 서버 측에 저장하는 작업을 하게 했다(~40 LOC).

이제 1을 링크해서 사용하는 서버 바이너리는, 2와 같이 배포하기만 하면, 크래시 발생 후에는 미리 지정한 특정 서버에 고스란히 덤프가 쌓이게 된다. 라이브 서비스 들어가기 전에는 테스트 망에서 RSS feed-notifier 류의 툴만 써 주면 이제 간단히 확인(…).

 

Update (2010-10-29)

전체 메모리 덤프 (MiniDumpWithFullMemory) 옵션을 줘도 풀 덤프가 남지 않아서 — 사실 이렇게 생각한게 모든 삽질의 시작 — 어제 저녁에 야근(…)했는데, 원인이 너무 허무 했다. 저 옵션으로 덤프를 남기게 했더니, 실제로는 덤프 디렉토리에 blah-blah.dmp 와 blah-blah-full.dmp 이렇게 덤프가 두 개 생성되더라 Orz. 그리고 “덤프 생성 완료” callback 에 전달되는 파일 이름은 저 중 앞 쪽의 덤프…

이건 소스 고쳐서 쓰거나, 컴파일 옵션?을 찾거나 해야 할 듯. 아니면 그냥 -full 붙이던가

  1. 실제로는 Google의 Chrome, Picasa, Earth,  그리고 Mozilla Firefox, Camino등에서 쓰고 있다고 한다 []
  2. 크래시가 일어나면 exception handler 자체의 스택 일부를 빼면 거의 아무것도 믿을 수 없게 된다; heap, 다른 스레드의 메모리, 다른 스레드 스택 등등 오염되어 제대로 참조할 수 없는 가능성이 크다 []

팀 세미나: Go Programming Language #4

어쩌다보니 세 번째 했던 건 안 올려놨다는 사실을 확인. 일단 그 내용은 대부분 지난 번 성능 평가 관련 글의 내용이라 일단 나중에 기회 되면 올리기로…

이번에는 Go 를 가지고 UDP 데이터그램을 적당히 변조해주는 프로그램인 troll을 재 구현하고, 그에 대한 기록을 남겨봤다.

Introduction to Go Programming Language #4

Google Go: 간단한 성능 평가

수요일에 있을 팀 세미나 준비하면서, Google Go로 간단한 병렬 프로그램을 짜고, 직렬(serial;sequential) 구현과 성능을 비교 해봤다. 일단 간단히 여기에 정리. 모든 테스트는 x64 버젼의 MacOSX 를 돌리는 MacBook(2008년에 산 녀석)/dual-core 에서 이루어 졌다.

매우 간단하게 병렬화 되는 알고리즘인, quicksort를 가지고 성능 테스트를 했다. pivot을 그냥 순열 중간에서 찍어내는 단순 무식한 방법으로 만들었음.

이하에선 대략 배열 길이가 512 보다 작으면 그냥 순차 알고리즘만 동작하게 했음.

Naïve 하게 시작

우선 처음엔 fork-join 하는 형태로 좀 많이 naïve 하게 짜봤다: 정수 400만개 정렬 시켰더니, goroutine 수가 너무 많다고 뻗음. (이건 내 코드의 버그였음). 더 이상 fork하지 않고 도는 threshold를 좀 높게 잡고(8192?) 돌렸더니 대략 1200ms 정도 걸리더라. 단순하게 그냥 짠 알고리즘을 싱글 스레드로 돌리면 약 2000ms. 거의 2 배의 스피드업이 있긴하다.

그래도 이건 좀 아니다 싶어서(…), Work-stealing queue를 짜기 시작.

Work-Stealing Queue

완전히 다 구현한건 아니고, 배열을 둘로 쪼갠 순간 다음과 같이 동작하게 했다.

배열의 앞 부분은 work-stealing queue로 전달하고, 나머지는 그 goroutine이 직접 정렬하게 했다. 물론 이것도 재귀적으로 적용되니까 전부 한 goroutine에선 이루어지지 않는다.

Work-Stealing Queue를 간단하게 구현한다고(…) 좀 가짜로 만들었다. 일단 큐를 스레드 별로 두지 않았다. 다만 자기 자기 큐에서 꺼낼 때의 LIFO 동작을 흉내내려고 전부 큐에 넣는게 아니라 마지막에 분할한 부분 배열은 자기가 직접 정렬한다. 그리고 다른 스레드의 큐에서 꺼내는걸 따라(?)해서 큐에서 꺼내는건 FIFO…

처음에 작업 종료되는걸 감지할 방법을 못찾고 해매다가, Queue에 넣은 작업 갯수 만큼 종료 신호를 받게 했다. 이것도 단순히 빈 슬라이스를 응답으로 보내게 해서 이거 숫자를 셌다(…).

대략 1100ms 정도 걸린다. 총 goroutine 수가 입력에 비례하는게 아니라, 코어 수에 맞춰놔서 naïve 구현처럼 panic() 함수 호출되는 일은 없었음;;;

C++이랑 비교

C++의 <algorithm>에 있는 sort 랑 비교해봤더니 너무 큰 차이가 난다. 대략 700ms 좀 안 걸리게 돌더라. 이건 무려 싱글 스레든데;;; 사실 이건 내 구현이 sort() 함수의 introsort 보다 예상 성능 자체가 낮아서 생기는 일이기도 하지만;;
내가 짠 알고리즘을 싱글 스레드로 돌린 경우 1580ms 정도 걸렸다.  (cf. Go는 2000ms)

intel tbb의 tbb::parallel_sort()를 사용한 경우 대략 350ms 쯤 걸린다. linear-speedup? 이게 가장 빠르긴 하구나.

Go 쪽에 썼던 코드를 그대로 넣고 돌렸더니 대략 1600ms. 그래도 코어 2개 쓰는 쪽이 빠르긴 하지.

요약

Go(single-thread): 2000ms
Go (parallel) : 1100ms

C++(single-thread; same algorithm): 1600 ms
C++(single-thread; std::sort() ) : 700ms
C++(2-threads; tbb::parallel_sort() ):  350ms

간단한 감상: 좀 더 최적화 할 여지가 있어 보인다. 심심풀이로 실제 물리 코어 수 보다 더 많은 MACPROCS를 지정했더니 성능이 꽤 빨리 내려간다. 생각보다 channel 통한 통신의 오버헤드는 크지 않아서 만족스러웠다. fork-join 과 worker-thread 비슷하게 짠 게 큰 차이는 안나는걸 보니… 반대로 goroutine은 아무리 많이 만들어도(한 6만개 만들어도 잘 돈다) 괜찮긴 하더라..

+ naïve 하게 짜면 망한다(???).

팀 세미나: Go Programming Language #2

지난 번에 이어, 팀 세미나에서 얘기했던 내용을 업로드.

Introduction to Go Programming Language #2

거의 일주일 전에 한거지만 업로드는 이제야…

지난 번에 받은 느낌은 C버젼의 Erlang 비슷한 언어였는데, 좀 더 쓰다보니 대략 Python 을 연상케한다.

  • Syntactic sugar라거나, http 모듈 구현 방식이라거나, duck-typing이나 다름 없는 interface 구조라거나
  • 하지만 python 을 컴파일 언어로 만들긴 힘드니, 상당한 제약이 들어가 있다
  • 그럼에도 불구하고 꽤나 편하게 만질 수 있었다 (System Programming 언어를 표방하는 애들 중엔 제일…)
  • C 랑 매우 잘 붙는 것도 거의(…)
  • C 와의 인터페이스로 쓰는 C pseudo-package 도 왠지 ctypes가 생각 나는 것이…

…이런 느낌?

이번엔 지난 번(4주 전)에 이어 간단한 웹 서버 모듈 짜고, 이걸로 뭔가 보여주려고 했는데, 예제 짜고나서 이걸 설명하려니 지난 번에 설명하지 못했던 개념들이 이거저거 나와서(…) 그것들과 C 언어 링킹, Goroutine 과 그 구현의 현재 문제점들, 그리고 간단한 웹 서버 모듈을 설명하는 걸로 마쳤다.

일단 웹 서버 모듈(http 팩키지)만 놓고 보면, python 의 BasicHTTPServer 처럼 http 팩키지의 핸들러를 적당히 등록하는 방식으로 만들 수 있어서 꽤나 편했다. python이랑 달리 아예 URI 별로 핸들러를 등록시키는 방식이라, 상대적으로 모듈 쪼개기가 쉬워보임. C랑 잘붙어서 기존 라이브러리 가져다 쓰기도 매우 편한 것 같고… C랑 붙이기 위해서 “C” 란 가짜 패키지를 (만드는 척해서) 사용하는데, C.struct_name, C.function_name 만으로 접근되는게 꽤 편했음. (다만 이를 위해 SWIG 처럼 cgo 란 툴로 팩키지 빌드를 하긴 해야함)

여튼 C 연결을 쓰는 sqlite 래퍼를 찾고(…), 여기에 http 팩키지로 만든 웹서버를 띄워서 간단한 북마크 저장소를 시연하고 이번 치 세미나는 끝. 다음 번 주제를 좀 고민하고 있는데, 웹 서버처럼 상대적으로 full-swing 하는게 쉽게 보이는 걸 좀 더 해볼지, 아니면 게임 서버처럼 서로 얽히고 섥힌(…) 녀석을 만들어 볼지 고민 중이다.