정보공간_1

[2기 부산 최은진] NaCl(Native Client) 소개 본문

IT 놀이터/Elite Member Tech & Talk

[2기 부산 최은진] NaCl(Native Client) 소개

알 수 없는 사용자 2012. 8. 18. 17:23

안녕하세요. 부산 멤버십 21-2기로 활동하고 있는 최은진입니다.

여러분들은 올해 11월에 Google HackFair가 열리는 건 알고 계시나요? Google 공식 한글 블로그에 자세한 내용이 설명되어 있습니다. 여기에서 확인해 보세요. 이 행사에 참가해서 자신의 프로젝트를 뽐내보는 건 어떨까요? 제가 이번에 소개해드릴 것은 여기서 소개된 Google의 기술 중 하나인 NaCl이라는 것입니다.



고등학교 화학시간에 자주 보던 염화나트륨이 아닙니다. NaCl이라는 이름만 들어봤을 때는 어떤 기술일까 매우 궁금했는데요. 원래 이름은 Native Client, 웹 브라우저에서 네이티브 코드를 운영하는 오픈소스 기술입니다. Native Client를 이용하면 개발자가 자신이 좋아하는 언어를 이용해 웹 애플리케이션을 향상시킬 수 있다고 합니다. 하지만 현재 지원하고 있는 Native 언어는 CC++두 가지 밖에 없습니다. 차후에 여러 언어에 대해서도 지원하도록 SDK가 업데이트 될 거라고 하니 기대해 볼만도 합니다.

Native Client 애플리케이션의 구조는 다음과 같습니다.


위 그림에서 보듯이 Native Client 애플리케이션은 HTML/자바스크립트 부분, Pepper API 부분, Navite Client 모듈 부분으로 나눌 수 있습니다. Pepper 플러그인 API를 이용해서 웹 브라우저의 자바스크립트 코드와 Native Client 모듈의 코드를 서로 이어줄 수 있습니다.

Google이 소개하고 있는 Native Client5가지 장점이 있습니다.


  1. 그래픽 및 오디오 등 : 2D 3D 그래픽을 렌더링하고, 오디오를 재생하고, 마우스와 키보드 이벤트에 응답하고, 여러 개의 스레드에서 실행되고, 메모리에 직접 액세스하는 네이티브 코드 모듈을 실행합니다. 이때, 플러그인을 설치하지 않아도 됩니다.

  2. 호환성 : 일단 앱을 작성한 다음에는 주요 플랫폼(Windows, Linux, Mac. 조만간 Chrome OS) 어디에서든 실행할 수 있습니다.

  3. 보안 : 데스크톱 앱이나 브라우저 플러그인을 설치하면 심각한 보안 위험이 발생하거나 잠재 사용자의 사용을 막을 수 있습니다. Native Client는 사용자의 시스템에서 리소스를 보호하도록 설계된 더블 샌드박스를 사용합니다. 이러한 구조는 컴파일된 네이티브 코드의 우수한 성능뿐 아니라 기존 웹 앱의 안전성을 제공하는데, 플러그인은 설치하지 않아도 됩니다.

  4. 손쉬운 웹 이전 경로 : 다수의 개발자와 업체는 수년 동안 기존 데스크톱 애플리케이션에서 작업해 왔는데, Native ClientCC++ (추후에 다른 언어도 포함)을 지원하여서 데스크톱 앱에서 웹 앱으로 이전하는 과정이 훨씬 더 쉬워졌습니다.

  5. 성능 : Native Client를 이용하면 데스크톱 앱과 맞먹는 속도로 앱이 실행됩니다. 따라서 콘솔 수준의 게임처럼 부담이 큰 애플리케이션을 브라우저에서 실행할 수 있습니다.


이러한 장점들을 바탕으로 많은 곳에 이용할 수 있는데 기존 데스크톱 어플리케이션을 웹 앱으로 쉽게 변경 가능하다거나, 웹 앱에서 기존의 소프트웨어 모듈을 사용할 수 있도록 할 수 있으며 많은 연산이 필요한 엔터프라이즈 어플리케이션, 멀티미디어 어플리케이션, 게임 등에 적용할 수 있습니다.



그럼 한번 Native Client SDK를 설치하고 간단한 예제를 작성해 보도록 하겠습니다. Windows 7 운영체제를 기준으로 설명하겠습니다.


1. 필요한 프로그램들을 설치합니다. Python 2.6 또는 2.7, Chrome이 설치되어 있어야 합니다.

먼저 Python이 설치되어 있는지 확인합니다. PythonNative Clinet SDK의 각종 툴들을 실행하는 데 필요합니다. 설치되어 있지 않다면 이곳에서  2.6.x 또는 2.7.x 버전을 다운로드 하여 설치한 뒤 PATH 환경변수에 Python 디렉토리 경로를 추가해 주어야 합니다.

Chrome 웹 브라우저는 여기에서 다운로드 할 수 있습니다.


2. Native Client SDK를 다운로드하고 압축을 풉니다.

이곳에서 SDK를 다운로드 하고 설치에 관한 자세한 내용을 확인할 수 있습니다.

다운로드 한 파일을 압축 해제하면 nacl_sdk라는 폴더가 나타납니다. 디렉토리 안에는 다음 그림과 같은 파일과 디렉토리들이 포함되어 있습니다.

cmd창에서 해당 디렉토리로 이동 후 naclsdk list 또는 naclsdk update을 입력하여 사용할 수 있는 번들 리스트를 확인하거나 새로운 번들을 다운로드 할 수 있습니다. naclsdk update명령을 입력해 번들을 업데이트 하도록 하겠습니다. 저는 새로 업데이트 된 pepper_21 번들을 사용해보도록 하겠습니다.


3. 로컬 서버를 시작합니다.

Native Client 모듈은 웹 서버에서 로드됩니다. SDK에 포함된 Python 웹 서버 또는 이미 시스템에 설치된 다른 웹 서버를 작동시킵니다. SDK에 포함된 웹 서버를 실행시키기 위해서는 nacl_sdk 디렉토리 경로에서 다음 명령을 실행합니다.


4. Native Client가 동작하도록 Chrome을 설정합니다.

Chrome의 버전은 위 항목에서 확인한 번들 버전 이상이어야 합니다. 버전이 맞는다면 Chrome에서 Native Client 플래그와 플러그인을 활성화 시킵니다.

먼저 주소창에 about:flags를 입력한 뒤 네이티브 클라이언트 항목으로 이동한 후 사용을 클릭하고 페이지 하단의 재실행 버튼을 클릭해 브라우저를 재시작 합니다. 그리고 다시 주소창에 about:plugins를 입력한 뒤 Native Client 항목으로 이동한 뒤 사용 중이 아니라면 사용을 클릭합니다.


5. 기본 소스 파일을 작성한 뒤 Native Client 모듈을 컴파일하고 실행합니다.

먼저 5가지의 기본 파일을 작성해야 합니다. 3번 항목에서 실행한 로컬 서버가 있는 디렉터리에 hello_tutorial 이라는 디렉토리를 생성한 뒤 이곳에 파일들을 작성하겠습니다.

 

hello_tutorial.html

<!DOCTYPE html>
<html>
<head>
  <title>hello_tutorial</title>

  <script type="text/javascript">
    hello_tutorialModule = null;
    statusText = 'NO-STATUS';

    function moduleDidLoad() {
      hello_tutorialModule = document.getElementById('hello_tutorial');
      updateStatus('SUCCESS');
    }

  
    function handleMessage(message_event) {
      alert(message_event.data);
    }

  
    function pageDidLoad() {
      if (hello_tutorialModule == null) {
        updateStatus('LOADING...');
      } else {       
        updateStatus();
      }
    }
   
    function updateStatus(opt_message) {
      if (opt_message)
        statusText = opt_message;
      var statusField = document.getElementById('status_field');
      if (statusField) {
        statusField.innerHTML = statusText;
      }
    }
  </script>
</head>
<body onload="pageDidLoad()">

<h1>Native Client Module hello_tutorial</h1>
<p> 
  <div id="listener">
    <script type="text/javascript">
      var listener = document.getElementById('listener');
      listener.addEventListener('load', moduleDidLoad, true);
      listener.addEventListener('message', handleMessage, true);
    </script>

    <embed name="nacl_module"
       id="hello_tutorial"
       width=0 height=0
       src="hello_tutorial.nmf"
       type="application/x-nacl" />
  </div>
</p>

<h2>Status</h2>
<div id="status_field">NO-STATUS</div>
</body>
</html>


hello_tutorial.cc

#include <cstdio>
#include <string>
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"

class hello_tutorialInstance : public pp::Instance {
 public:
  explicit hello_tutorialInstance(PP_Instance instance) : pp::Instance(instance) {}
  virtual ~hello_tutorialInstance() {}
 
  virtual void HandleMessage(const pp::Var& var_message) {}
};

class hello_tutorialModule : public pp::Module {
 public:
  hello_tutorialModule() : pp::Module() {}
  virtual ~hello_tutorialModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new hello_tutorialInstance(instance);
  }
};

namespace pp {
Module* CreateModule() {
  return new hello_tutorialModule();
}
}


hello_tutorial.nmf

{
  "program": {
    "x86-64": {"url": "hello_tutorial_x86_64.nexe"},
    "x86-32": {"url": "hello_tutorial_x86_32.nexe"}
  }
}


Makefile (들여쓰기는 탭 하나 입니다.)

# Copyright (c) 2012 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

PROJECT:=hello_tutorial
LDFLAGS:=-lppapi_cpp -lppapi
CXX_SOURCES:=$(PROJECT).cc

THIS_MAKEFILE:=$(abspath $(lastword $(MAKEFILE_LIST)))
NACL_SDK_ROOT?=$(abspath $(dir $(THIS_MAKEFILE))../..)

WARNINGS:=-Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
CXXFLAGS:=-pthread -std=gnu++98 $(WARNINGS)

OSNAME:=$(shell python $(NACL_SDK_ROOT)/tools/getos.py)
TC_PATH:=$(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_x86_newlib)
CXX:=$(TC_PATH)/bin/i686-nacl-g++

CYGWIN ?= nodosfilewarning
export CYGWIN



all: $(PROJECT)_x86_32.nexe $(PROJECT)_x86_64.nexe

x86_32_OBJS:=$(patsubst %.cc,%_32.o,$(CXX_SOURCES))
$(x86_32_OBJS) : %_32.o : %.cc $(THIS_MAKE)
    $(CXX) -o $@ -c $< -m32 -O0 -g $(CXXFLAGS)

$(PROJECT)_x86_32.nexe : $(x86_32_OBJS)
    $(CXX) -o $@ $^ -m32 -O0 -g $(CXXFLAGS) $(LDFLAGS)

x86_64_OBJS:=$(patsubst %.cc,%_64.o,$(CXX_SOURCES))
$(x86_64_OBJS) : %_64.o : %.cc $(THIS_MAKE)
    $(CXX) -o $@ -c $< -m64 -O0 -g $(CXXFLAGS)

$(PROJECT)_x86_64.nexe : $(x86_64_OBJS)
    $(CXX) -o $@ $^ -m64 -O0 -g $(CXXFLAGS) $(LDFLAGS)

.PHONY: RUN
RUN: all
    python ../httpd.py


make.bat

@..\..\tools\make.exe %*


모든 파일의 작성이 끝나면 해당 디렉토리에서 make.bat 파일을 실행해 Native Client 모듈을 컴파일 합니다.

컴파일이 완료되면 다음과 같은 Native Client 모듈 실행 파일이 생성됩니다.

이제 확인해 보도록 하겠습니다.

크롬에서 http://localhost:5103/hello_tutorial.html 를 입력해 위에서 작성한 hello_tutorial.html 페이지에서 Native Client 모듈을 로드하는 것을 확인할 수 있습니다. 제대로 로드되었다면 다음과 같은 페이지가 나타날 것입니다.

 

6. 마지막으로 모듈을 로드했을 때 메시지를 띄워보도록 하겠습니다.

페이지가 로드 되었을 때 웹 페이지의 자바스크립트 코드에서 Native Client 모듈로 메시지를 보내고 그 메시지를 받은 Native Client 모듈이 메시지를 보내 응답하는 과정입니다. 

작성한 hello_tutorial.html 파일에서 자바스크립트 함수 moduleDidLoad()를 찾아 다음 내용을 함수 마지막 부분에 추가시킵니다.

//Send a message to the NaCl module.
hello_tutorialModule.postMessage('hello');


다음으로 hello_tutorial.cc 파일에서 #include 명령문 뒤에 다음 코드를 추가시킵니다.

namespace{
// The expected string sent by the browser.
constchar*const kHelloString ="hello";
// The string sent back to the browser upon receipt of a message
// containing "hello".
constchar*const kReplyString ="hello from NaCl";
}// namespace


그리고 HandleMessage() 함수를 찾아 다음 코드를 함수에 추가시킵니다.

if(!var_message.is_string())
    return;
std::string message = var_message.AsString();
pp::Var var_reply;
if(message == kHelloString){
    var_reply = pp::Var(kReplyString);
    PostMessage(var_reply);
}


파일을 저장하고 make.bat를 실행시켜 다시 컴파일 합니다.

http://localhost:5103/hello_tutorial.html 에서 hello_tutorial.html 을 다시 로드시켜 결과를 확인합니다. 아래와 같은 메시지 창이 뜬다면 성공한 것입니다.



지금까지 GoogleNative Client에 대해서 알아보았습니다. 이런 기술을 활용해서 3D 게임과 같은 고사양의 어플리케이션을 웹 페이지에서 실행할 수 있다면 정말 재미있을 것 같습니다. Native Client에 대해 더 자세한 내용을 확인하고 싶다면 Google Devlopers에서 Native Client 소개 페이지를 참고하세요.

링크는 https://developers.google.com/native-client/dev/?hl=ko 입니다.




이미지 출처 및 참고자료