由于node接口有限,一些网络基层操作还得依靠c++来, 可能也是为了避免大家那么卷而选择保护大家吧,不说二话,咱直接上代码。下面会附上node调用c++的教程
node代码
let Pcap = require('./build/Release/Pcap.node')
let Capture = new Pcap.Capture()
Capture.Start({
OnRecv: function( buffer ) {
let bytes = []
for (let index = 0; index < buffer.length; index++) {
let element = buffer[index]
if ( buffer[index] < 0 ) {
element = 256 + element
}
bytes.push( element );
}
}
}
capture.h
#ifndef CAPTURE_H
#define CAPTURE_H
#include <napi.h>
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mstcpip.h>
#include <comdef.h>
#pragma comment(lib, "ws2_32.lib")
class Capture : public Napi::ObjectWrap<Capture> {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
Capture(const Napi::CallbackInfo& info);
private:
void Start(const Napi::CallbackInfo& info);
};
#endif
capture.cc
#include "capture.h"
int log(std::string str) {
int lastError = WSAGetLastError();
LPTSTR lpMsgBuf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL) != 0) {
// 输出错误信息
std::cout << str << "[" << lastError << "]" << (char*)_bstr_t(lpMsgBuf) << std::endl;
LocalFree(lpMsgBuf);
}
return lastError;
}
Napi::Object Capture::Init(Napi::Env env, Napi::Object exports) {
Napi::Function func = DefineClass(env, "Capture", {
InstanceMethod("Start", &Capture::Start),
});
Napi::FunctionReference* constructor = new Napi::FunctionReference();
*constructor = Napi::Persistent(func);
env.SetInstanceData(constructor);
exports.Set("Capture", func);
return exports;
}
Capture::Capture(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Capture>(info) {
}
void Capture::Start(const Napi::CallbackInfo& info) {
WSADATA wsa;
int errror;
if (errror = WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
log("WSAStartup: ");
}
char name[100];
gethostname(name, sizeof(name));
struct addrinfo *result = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_IP;
if (errror = getaddrinfo(name, 0, &hints, &result) != 0) {
std::cout << errror << std::endl;
log("getaddrinfo: ");
WSACleanup();
}
SOCKET rawSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (rawSocket == INVALID_SOCKET) {
std::cout << rawSocket << std::endl;
log("socket: ");
freeaddrinfo(result);
WSACleanup();
}
// struct sockaddr_in6 addr;
// addr.sin6_family = AF_INET6;
// addr.sin6_port = 0;
// addr.sin6_flowinfo = 0;
// addr.sin6_addr = in6addr_any;
// addr.sin6_scope_id = 0;
if (errror = bind(rawSocket, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR) {
// if (errror = bind(rawSocket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
std::cout << errror << std::endl;
log("bind: ");
freeaddrinfo(result);
closesocket(rawSocket);
WSACleanup();
}
// BOOL bValue = TRUE;
// if (errror = setsockopt(rawSocket, result->ai_protocol, IP_HDRINCL, (char*)&bValue, sizeof(bValue)) == SOCKET_ERROR) {
// std::cout << errror << std::endl;
// log("setsockopt: ");
// freeaddrinfo(result);
// closesocket(rawSocket);
// WSACleanup();
// }
DWORD dwValue = RCVALL_ON;
if (errror = ioctlsocket(rawSocket, SIO_RCVALL, &dwValue) != 0) {
std::cout << errror << std::endl;
log("ioctlsocket: ");
freeaddrinfo(result);
closesocket(rawSocket);
WSACleanup();
}
Napi::Env env = info.Env();
Napi::Object options = info[0].As<Napi::Object>();
Napi::Function OnRecv = options.Get(Napi::String::New(env, "OnRecv")).As<Napi::Function>();
char buff[4096];
int count;
while (true) {
count = recv(rawSocket, buff, 4096, 0);
std::cout << count << std::endl;
if (count == SOCKET_ERROR) {
log( "recv: " );
}
else {
Napi::Array jsArray = Napi::Array::New(env, count);
for (size_t i = 0; i < count; ++i) {
jsArray.Set(i, Napi::Number::New(env, buff[i]));
}
OnRecv.Call(env.Global(), {
jsArray
});
}
}
freeaddrinfo(result);
closesocket(rawSocket);
WSACleanup();
}
NODE_API_ADDON(Capture)
相信一脸懵逼的你已经看到了这里,那么附上咱们node调用c++的教程哈
1.安装node的头文件api
npm i node-addon-api
2.新建源码文件:
hello.cc
#include <napi.h>
class HelloAddon : public Napi::Addon<HelloAddon> {
public:
HelloAddon(Napi::Env env, Napi::Object exports) {
DefineAddon(exports,
{InstanceMethod("hello", &HelloAddon::Hello, napi_enumerable)});
}
private:
Napi::Value Hello(const Napi::CallbackInfo& info) {
return Napi::String::New(info.Env(), "world");
}
};
NODE_API_ADDON(HelloAddon)
3.新建构建与编译的配置文件:
binding.gyp
{
"targets": [
{
"target_name": "hello",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "hello.cc" ],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
'defines': ['NAPI_DISABLE_CPP_EXCEPTIONS'],
}
]
}
4.安装node-gyp全局命令
npm -g node-gyp
5.管理员运行cmd, 然后来到这个项目目录 ( node-gyp需要管理员权限还有环境变量 )
6.生成构建文件, 会生成build目录, 里面会根据当前系统生成对应的一些文件, 比如linux会生成Makefile, windows估计会生成vs的sln解决方案
node-gpy configure
7.开始编译, 使用node-gyp自带的编译即可
node-gyp build
( 注意:6.7可以合并成一条命令 node-gyp rebuild, 该命令会清除编译缓存并重新生成 )
8.生成的文件在 build/release/helle.node
在js使用只需要require('build/release/helle')就行
9.新建hello.js
let hello = require( './build/Release/hello' )
console.log(hello.hello())