Node.js는 JavaScript를 사용하여 백엔드를 작성하는 데 가장 좋은 효과가 있으며 더 많은 노력을 기울일 가치가 있습니다. 그러나 직접 사용할 수없는 일부 기능이나 전혀 구현할 수없는 모듈이 필요한 경우 C/C ++ 라이브러리에서 그러한 성과를 도입 할 수 있습니까? 대답은 예입니다. 플러그인을 작성하고 JavaScript 코드에서 다른 코드 기반 리소스를 사용하기 만하면됩니다. 오늘의 문의 여정을 함께 시작합시다.
소개하다
Node.js가 공식 문서에서 알 수 있듯이 플러그인은 동적으로 연결되는 공유 객체이며, 이는 JavaScript 코드를 C/C ++ 라이브러리와 연결할 수 있습니다. 즉, C/C ++ 라이브러리에서 모든 것을 참조하고 플러그인을 만들어 Node.js에 통합 할 수 있습니다.
예를 들어, 표준 std :: 문자열 객체에 대한 캡슐화를 생성합니다.
준비
글쓰기를 시작하기 전에 후속 모듈 컴파일에 필요한 모든 자료를 준비해야합니다. 모든 사람은 노드 산과 모든 종속성이 필요합니다. 다음 명령을 사용하여 Node-Gyp를 설치할 수 있습니다.
npm install -g node -gyp
종속성 측면에서 UNIX 시스템에 대해 다음 프로젝트를 준비해야합니다. • Python (버전 2.7, 3.x가 제대로 작동 할 수 없습니다).
• 만들다
• C ++ 컴파일러 툴체인 (예 : GPP 또는 G ++)
예를 들어, Ubuntu에서는 다음 명령을 사용하여 위의 모든 프로젝트를 설치할 수 있습니다 (Python 2.7은 사전 설치되어야 함).
sudo apt-get 설치 빌드 필수 정보
Windows 시스템 환경에서 필요한 것은 다음과 같습니다.
• Python (버전 2.7.3, 3.x 버전은 정상적으로 작동 할 수 없습니다)
• Microsoft Visual Studio C ++ 2010 (Windows XP/Vista 용)
• Windows 데스크탑 용 Microsoft Visual Studio C ++ 2012 (Windows 7/8 용)
강조하기 위해 Visual Studio의 Express 버전도 정상적으로 작동 할 수 있습니다.
binding.gyp 파일
이 파일은 Node-Gyp에서 사용되며 플러그인의 적절한 빌드 파일을 생성하도록 설계되었습니다. Wikipedia에서 제공하는 .gyp 파일 설명 문서를 보려면 여기를 클릭 할 수 있지만 오늘 사용하려는 예제는 매우 간단하므로 다음 코드를 사용하면됩니다.
{ "targets": [{ "target_name": "stdstring", "소스": [ "addon.cc", "stdstring.cc"]}}Target_name을 원하는대로 설정할 수있는 곳. 소스 배열에는 플러그인이 사용해야하는 모든 소스 파일이 포함되어 있습니다. 이 예에서는 addon.cc도 포함되어 있으며 플러그인과 stdstring.cc를 컴파일하는 데 필요한 코드와 캡슐화 클래스를 수용하는 데 사용됩니다.
stdstringwrapper 클래스
첫 번째 단계는 stdstring.h 파일에서 우리 자신의 클래스를 정의하는 것입니다. C ++ 프로그래밍에 익숙하다면 다음 두 줄의 코드에 익숙하지 않을 것입니다.
#ifndef stdstring_h #define stdstring_h
이것은 표준에 속합니다. 다음으로 포함 범주에 다음 두 헤더를 포함해야합니다.
#포함하다
#포함하다
첫 번째는 STD :: 문자열 클래스를 목표로하고 두 번째는 모든 노드 및 V8 관련 컨텐츠에 대한 ACT를 포함합니다.
이 단계가 완료되면 수업을 선언 할 수 있습니다.
클래스 stdstringwrapper : public node :: ObjectWrap {
플러그인에 포함하려는 모든 클래스의 경우 Node :: ObjectWrap 클래스를 확장해야합니다.
이제이 수업의 사유 재산을 정의 할 수 있습니다.
비공개 : std :: string* s_; 명시 적 stdstringwrapper (std :: string s = ""); ~ stDStringWrapper ();
생성자 및 분석 기능 외에도 std :: string에 대한 포인터를 정의해야합니다. 이것은이 기술의 핵심이며 C/C ++ 코드베이스를 노드에 연결하는 데 사용될 수 있습니다. C/C ++ 클래스의 개인 포인터를 정의 하고이 포인터를 사용하여 모든 후속 방법에서 작업을 구현합니다.
이제 우리는 생성자 정적 속성을 선언합니다.이 속성은 v8에서 만든 클래스에 대한 기능을 제공 할 것입니다.
정적 V8 :: 영구 생성자;
관심있는 친구들은 여기를 클릭하여 템플릿 설명 계획을 참조하십시오.
이제 우리는 또한 위에서 언급 한 생성자에게 할당 될 새로운 방법이 필요하며 V8은 다음을 초기화합니다.
정적 v8 :: new (const v8 :: arguments & args);
V8에서 행동하는 모든 기능은 다음 요구 사항을 따라야합니다. V8 :: 인수에 대한 참조를 수락하고 v8 :: hange> v8 :: value>-이 V8이 강한 유형 C ++ 인코딩을 사용할 때 약한 유형 JavaScript를 처리하는 방법입니다.
그런 다음 다른 두 가지 방법을 객체의 프로토 타입에 삽입해야합니다.
정적 v8 :: 핸들 ADD (const v8 :: arguments & args); 정적 v8 :: 핸들 토스트 링 (const v8 :: arguments & args);
여기서 toString () 메소드를 사용하면 일반 JavaScript 문자열과 함께 사용할 때 [Object Object]의 값 대신 S_의 값을 얻을 수 있습니다.
마지막으로, 초기화 방법 (이 방법은 V8에 의해 호출되고 생성자 함수에 할당됨)을 소개하고 닫기 가드를 포함시킵니다.
public : 정적 void init (v8 :: 핸들 내보내기); }; #endif
JavaScript 모듈에서 내보내기 개체의 역할은 Module.Exports와 같습니다.
stdstring.cc 파일, 생성자 및 구문 분석 기능
이제 stdstring.cc 파일을 만듭니다. 먼저 헤더를 포함해야합니다.
#include "stdstring.h"
다음은 생성자의 속성을 정의합니다 (정적 함수에 속하기 때문에) :
v8 :: 영구적 인 stdstringwrapper :: 생성자;
클래스를 제공하는이 생성자는 S_ 속성을 할당합니다.
stdstringwrapper :: stdstringwrapper (std :: string s) {s_ = new std :: string (s); }구문 분석 기능은 메모리 오버플로를 피하기 위해이를 삭제합니다.
stDStringWrapper :: ~ stDStringWrapper () {delete s_; }또한, 그러한 상황이 예외를 일으킬 때마다 위의 작업을 기억하거나 공유 포인터를 사용하므로 새로 할당 된 모든 컨텐츠를 새로 삭제해야합니다.
초기 방법
이 방법은 V8에 의해 호출되며 클래스를 초기화하기위한 것입니다 (생성자를 할당하고 Exports Object에서 JavaScript에서 사용하려는 모든 컨텐츠를 배치).
void stdstringwrapper :: init (v8 :: 핸들 내보내기) {
먼저 새 방법에 대한 함수 템플릿을 만들어야합니다.
v8 :: 로컬 tpl = v8 :: functiontemplate :: new (new);
이것은 JavaScript의 새로운 기능과 약간 유사합니다. 자사 자바 스크립트 클래스를 준비 할 수 있습니다.
이제 실제 요구에 따라 함수 이름을 설정할 수 있습니다 (이 단계를 놓치면 생성자는 익명 상태, 즉 이름은 function somename () {} 또는 function () {})입니다.
tpl-> setclassName (v8 :: string :: newsymbol ( "stdstring"));
v8 :: string :: newsymbol ()을 사용하여 속성 이름에 대한 특수 유형 문자열을 만듭니다. 이는 엔진 작동에 약간의 시간을 절약합니다.
그런 다음 클래스 인스턴스가 포함 된 필드 수를 설정해야합니다.
tpl-> instancetemplate ()-> setinternalfieldCount (2);
두 가지 방법이 있습니다. add ()와 tostring ()이 있으므로 숫자를 2로 설정합니다. 이제 기능 프로토 타입에 고유 한 메소드를 추가 할 수 있습니다.
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ( "add"), v8 :: functiontemplate :: new (add)-> getFunction ());
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ( "tostring"), v8 :: functiontemplate :: new (tostring)-> getFunction ());
코드 의이 부분은 상당히 크게 보이지만 신중하게 관찰하는 한 규칙을 찾을 수 있습니다. 우리는 tpl-> prototypetemplate ()-> set ()를 사용하여 각 메소드를 추가합니다. 또한 v8 :: string :: newsymbol ()을 사용하여 이름과 functiontemplate를 제공합니다.
마지막으로 생성자 클래스 속성 내에 생성자를 내보내기 객체에 배치 할 수 있습니다.
생성자 = v8 :: 영구 :: new (tpl-> getFunction ()); Exports-> set (v8 :: string :: newsymbol ( "stdstring"), 생성자); }
새로운 방법
이제 우리가해야 할 일은 javaScript 객체와 동일한 방식으로 작동하는 메소드를 정의하는 것입니다.
v8 :: handle stdstringwrapper :: new (const v8 :: arguments & args) {먼저 그 범위를 만들어야합니다.
v8 :: 핸들 스코프 범위;
그런 다음 Args 객체의 .isconstructCall () 메소드를 사용하여 새 키워드를 사용하여 생성자를 호출 할 수 있는지 확인할 수 있습니다.
if (args.isconstructCall ()) {가능하면 먼저 매개 변수를 std :: string으로 전달합니다.
v8 :: string :: utf8value str (args [0]-> tostring ()); std :: 문자열 s (*str);
... 따라서 캡슐화 된 클래스의 생성자로 전달할 수 있습니다.
stdstringwrapper* obj = 새로운 stdstringwrapper (s);
그런 다음 이전에 만든 객체의 .wrap () 메소드를 사용하여 (Node :: ObjectWrap에서 상속)이 변수에 할당 할 수 있습니다.
obj-> 랩 (args.this ());
마지막으로 새로 생성 된이 개체를 반환 할 수 있습니다.
return args.this ();
새로 기능을 호출 할 수없는 경우 생성자를 직접 호출 할 수도 있습니다. 다음으로, 우리가하고 싶은 것은 매개 변수 수에 대한 상수를 설정하는 것입니다.
} else {const int argc = 1;이제 우리는 자체 매개 변수를 사용하여 배열을 만들어야합니다.
v8 :: 로컬 Argv [argc] = {args [0]};그런 다음 생성자 -> NewInstance 메소드의 결과를 SCOPE.CLOSE로 전달하여 나중에 객체가 역할을 수행 할 수 있도록하십시오 (SCOPE.CLOSE 기본적으로 객체 처리 핸들을 더 높은 범위로 이동시켜 모든 사람이 유지할 수 있습니다. 기능이 효력을 취하는 방식이기도합니다).
return scope.close (생성자-> newinstance (argc, argv)); }}
메소드를 추가하십시오
이제 모든 사람이 객체의 내부 std :: string에 컨텐츠를 추가 할 수 있도록 추가 메소드를 만들어 봅시다.
v8 :: handle stdstringwrapper :: add (const v8 :: arguments & args) {먼저 기능을위한 범위를 생성하고 매개 변수를 이전과 같이 std :: string으로 변환해야합니다.
v8 :: 핸들 스코프 범위; v8 :: string :: utf8value str (args [0]-> tostring ()); std :: 문자열 s (*str);
이제 우리는 객체를 풀어야합니다. 우리는 또한이 역 캡슐화 작업을 수행했습니다. 이번에는이 변수에서 객체에 대한 포인터를 얻을 것입니다.
stDStringWrapper* obj = ObjectWrap :: UNGRAP (args.this ());
그런 다음 s_ 속성에 액세스하고 .append () 메소드를 사용할 수 있습니다.
obj-> s _-> Append (s);
마지막으로 S_ 속성의 현재 값을 반환합니다 (SCOPE.CLOSE를 다시 사용해야 함) :
return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
v8 :: string :: new () 메소드는 char 포인터를 값으로 만 허용 할 수 있으므로 OBJ-> S _-> C_STR ()를 사용하여 가져와야합니다.
현재 플러그인 폴더에서 빌드 디렉토리를 작성해야합니다.
시험
이제 플러그인을 테스트 할 수 있습니다. 플러그인 디렉토리에서 test.js 파일과 필요한 컴파일 라이브러리를 만듭니다 (.Node 확장자를 직접 건너 뛸 수 있음) :
var addon = require ( './ build/release/addon');
다음으로 객체에 대한 새 인스턴스를 만듭니다.
var test = new addon.stdstring ( 'test');
다음으로 문자열로 추가하거나 변환하는 것과 같은 수행하십시오.
test.add ( '!'); console.log ( 'test/'의 내용 : %s ', 테스트);
실행 후 콘솔에서 다음 실행 결과가 표시됩니다.
결론적으로
이 튜토리얼을 읽은 후 C/C ++ 라이브러리를 기반으로 사용자 지정 Node.js 플러그인을 매우 어려운 작업으로 작성하고 테스트 할 수 있기를 바랍니다. 이 기술을 사용하여 거의 모든 C/C ++ 라이브러리를 Node.js에 쉽게 도입 할 수 있습니다. 원한다면 실제 요구에 따라 플러그인에 더 많은 기능을 추가 할 수도 있습니다. STD :: String은 많은 방법을 제공하며 운동 자료로 사용할 수 있습니다.
실용적인 링크
관심있는 친구는 Node.js 플러그인 개발, V8 및 C 이벤트 루프 라이브러리와 관련된 더 많은 리소스 및 세부 사항에 대해서는 다음 링크를 확인할 수 있습니다.
• node.js 플러그인 문서
• V8 문서
• Github의 Libuv (C 이벤트 루프 라이브러리)
영어 : http://code.tutsplus.com/tutorials/writing-nodejs-addons--cms-21771