libuv 是node.js作者写的,是 Node 的新跨平台抽象层,用于抽象 Windows 的 IOCP 及 Unix 的 libev。作者打算在这个库的包含所有平台的差异性。
特性: ibuv 严格使用 异步 、 事件驱动 的编程风格。其核心工作是提供事件循环及基于 I/O 或其他活动事件的回调机制,非阻塞 TCP 套接字 非阻塞命名管道 UDP 定时器 子进程生成 通过 uv_getaddrinfo 实现异步 DNS 异步文件系统 API:uv_fs_* 高分辨率时间:uv_hrtime 正在运行程序路径查找:uv_exepath 线程池调度:uv_queue_work TTY控制的ANSI转义代码: uv_tty_t 文件系统事件现在支持 inotify, ReadDirectoryChangesW 和 kqueue。很快会支持事件端口:uv_fs_event_t 进程间的 IPC 与套接字共享:uv_write2
自己写的一个小例子:
client.h
点击(此处)折叠或打开
-
#ifndef CLIENTTEST_H_
-
#define CLIENTTEST_H_
-
-
#include <v8.h>
-
#include <node.h>
-
#include <node_object_wrap.h>
-
-
using namespace node;
-
using namespace v8;
-
-
class ClientTest : ObjectWrap {
-
public:
-
ClientTest(){}
-
~ClientTest(){}
-
//构造并初始化对外的函数或方法给js使用
-
static void Init(Handle<Object> target);
-
//对外的构造对象的New函数
-
static Handle<Value> New(const Arguments& args);
-
//对外的异步方法
-
static Handle<Value> connect(const Arguments& args);
-
//异步工作函数
-
static void connectWork(uv_work_t* req);
-
//异步工作函数结束之后调用的函数
-
static void afterConnect(uv_work_t* req, int status);
-
//测试函数
-
static Handle<Value> test(const Arguments& args);
-
-
//获取构造函数,需要自己释放
-
static Persistent<FunctionTemplate> constructorTemplate;
-
-
};
-
- #endif
点击(此处)折叠或打开
-
#ifndef BATON_H_
-
#define BATON_H_
-
#include <node.h>
-
#include <v8.h>
-
#include <uv.h>
-
#include <string>
-
#include "client.h"
-
-
using namespace v8;
-
-
class Baton{
-
public:
-
Baton(ClientTest*c,Handle<Function>*callback);
-
~Baton();
-
/*存放回调函数,使用persistent来声明,让程序不会在函数结束后自动回收
-
当回调成功后,使用discope释放空间
-
*/
-
Persistent<Function> callback;
-
-
-
//错误信息
-
bool err;
-
std::string *errMsg;
-
//运行需要的参数
-
ClientTest *client;
-
std::string hostname;
-
std::string user;
-
std::string password;
-
-
-
};
- #endif
点击(此处)折叠或打开
-
#ifndef _util_h_
-
#define _util_h_
-
-
#include <string>
-
#include <sstream>
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
//判断参数是否是bool类型,如果不是,做异常处理
-
#define REQ_BOOL_ARG(I, VAR) \
-
if (args.Length() <= (I) || !args[I]->IsBoolean()) \
-
return ThrowException(Exception::TypeError(String::New("Argument " #I " must be a bool"))); \
-
bool VAR = args[I]->IsTrue();
-
//判断参数是否是string类型,并作转化
-
#define REQ_STRING_ARG(I, VAR) \
-
if (args.Length() <= (I) || !args[I]->IsString()) \
-
return ThrowException(Exception::TypeError(String::New("Argument " #I " must be a string"))); \
-
Local<String> VAR = Local<String>::Cast(args[I]);
-
//判断参数是否是数组类型
-
#define REQ_ARRAY_ARG(I, VAR) \
-
if (args.Length() <= (I) || !args[I]->IsArray()) \
-
return ThrowException(Exception::TypeError(String::New("Argument " #I " must be an array"))); \
-
Local<Array> VAR = Local<Array>::Cast(args[I]);
-
//判断参数是否是函数类型
-
#define REQ_FUN_ARG(I, VAR) \
-
if (args.Length() <= (I) || !args[I]->IsFunction()) \
-
return ThrowException(Exception::TypeError(String::New("Argument " #I " must be a function"))); \
-
Local<Function> VAR = Local<Function>::Cast(args[I]);
-
//判断参数是否是对象类型并将对象转化为Local<Object>
-
#define REQ_OBJECT_ARG(I, VAR) \
-
if (args.Length() <= (I) || !args[I]->IsObject()) \
-
return ThrowException(Exception::TypeError(String::New("Argument " #I " must be an object"))); \
-
Local<Object> VAR = Local<Object>::Cast(args[I]);
-
//给对象的某一字符串变量赋值var是变量,key是用来赋值的关键字
-
#define OBJ_GET_STRING(OBJ, KEY, VAR) \
-
{ \
-
Local<Value> __val = OBJ->Get(String::New(KEY)); \
-
if(__val->IsString()) { \
-
String::Utf8Value __utf8Val(__val); \
-
VAR = *__utf8Val; \
-
} \
-
}
-
-
//给对象的某一数值类型赋值
-
#define OBJ_GET_NUMBER(OBJ, KEY, VAR, DEFAULT) \
-
{ \
-
Local<Value> __val = OBJ->Get(String::New(KEY)); \
-
if(__val->IsNumber()) { \
-
VAR = __val->ToNumber()->Value(); \
-
} \
-
else if(__val->IsString()) { \
-
String::Utf8Value __utf8Value(__val); \
-
VAR = atoi(*__utf8Value); \
-
} else { \
-
VAR = DEFAULT; \
-
} \
-
}
-
-
- #endif
点击(此处)折叠或打开
-
#include <iostream>
-
#include "client.h"
-
#include "baton.h"
-
#include "utils.h"
-
-
Persistent<FunctionTemplate> ClientTest::constructorTemplate;
-
void ClientTest::Init(Handle<Object> target)
-
{
-
HandleScope scope;
-
-
//定义一个函数模板
-
Local<FunctionTemplate> t = FunctionTemplate::New(New);
-
constructorTemplate = Persistent<FunctionTemplate>::New(t);
-
constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
-
constructorTemplate->SetClassName(String::NewSymbol("ClientTestTest"));
-
-
NODE_SET_PROTOTYPE_METHOD(constructorTemplate,"connection",connect);
-
NODE_SET_PROTOTYPE_METHOD(constructorTemplate,"test",test);
-
target->Set(String::NewSymbol("ClientTest"),constructorTemplate->GetFunction());
-
}
-
-
Handle<Value> ClientTest::New(const Arguments& args)
-
{
-
HandleScope scope;
-
ClientTest *client = new ClientTest();//实例化一个Client对象,用指针client指向
-
client->Wrap(args.This()); //包裹client对象
-
return scope.Close(args.This());//返回这个对象给外部使用
-
}
-
-
Handle<Value> ClientTest::connect(const Arguments& args)
-
{
-
HandleScope scope;
-
//把第一个参数js对象转换成C++可用的对象
-
REQ_OBJECT_ARG(0, settings);
-
//回调函数的判断并转化
-
REQ_FUN_ARG(1, callback);
-
//将node.js的对象包装成C++对象
-
ClientTest* client = ObjectWrap::Unwrap<ClientTest>(args.This());
-
//构建一个baton 对象
-
Baton* baton = new Baton(client, &callback);
-
//获取对象字符串并赋值
-
OBJ_GET_STRING(settings, "hostname", baton->hostname);
-
OBJ_GET_STRING(settings, "user", baton->user);
-
OBJ_GET_STRING(settings, "password", baton->password);
-
-
client->Ref();
-
uv_work_t* req = new uv_work_t();
-
req->data = baton;
-
//将任务加入到工作队列
-
uv_queue_work(uv_default_loop(), req, connectWork, (uv_after_work_cb)afterConnect);
-
//返回
-
return scope.Close(Undefined());
-
-
}
-
void ClientTest::connectWork(uv_work_t* req)
-
{
-
//Baton 类型指针做转化
-
Baton *baton = static_cast<Baton*>(req->data);
-
baton->errMsg = NULL;
-
baton->err = false;
-
//模拟工作,这里省去了异常处理
-
std::cout<<"I am connecting!"<<std::endl;
-
}
-
-
void ClientTest::afterConnect(uv_work_t* req, int status)
-
{
-
HandleScope scope;
-
Baton* baton = static_cast<Baton*>(req->data);
-
baton->client->Unref();
-
Handle<Value> argv[2];
-
if(baton->err) {
-
argv[0] = Exception::Error(String::New(baton->errMsg->c_str()));
-
argv[1] = Undefined();
-
} else {
-
argv[0] = Undefined();
-
//构造client对象
-
Handle<Object> client = ClientTest::constructorTemplate->GetFunction()->NewInstance();
-
//对象作为回调函数第二个参数
-
argv[1] = client;
-
}
-
//执行回调返回
-
node::MakeCallback(Context::GetCurrent()->Global(), baton->callback, 2, argv);
-
//删除对象
-
delete baton;
-
}
-
-
Handle<Value> ClientTest::test(const Arguments& args)
-
{
-
HandleScope scope;
-
return scope.Close(String::New("Hello World!"));
- }
点击(此处)折叠或打开
-
#include "baton.h"
-
using namespace v8;
-
-
Baton::Baton(ClientTest*c,Handle<Function> *callback)
-
{
-
this->client = c;
-
if (callback!=NULL)
-
{
-
this->callback = Persistent<Function>::New(*callback);
-
}
-
else
-
{
-
this->callback = Persistent<Function>();
-
}
-
this->err = false;
-
this->errMsg = NULL;
-
this->hostname = "127.0.0.1";
-
this->user = " ";
-
this->password = " ";
-
}
-
Baton::~Baton()
-
{
-
callback.Dispose();
-
if(errMsg)
-
{
-
delete errMsg;
-
}
- }
点击(此处)折叠或打开
-
#include "baton.h"
-
#include "client.h"
-
-
-
extern "C" {
-
static void init(Handle<Object> target) {
-
ClientTest::Init(target);
-
-
}
-
NODE_MODULE(asyn,init);
- }
js代码:
点击(此处)折叠或打开
-
var addon = require('./asyn');
-
-
var connData = {
-
"hostname":'localhost',
-
"user":'admin',
-
"passwd":'admin123'
-
};
-
var conn = new addon.ClientTest();
-
-
var res = conn.connection(connData,function(err,connect){
-
if (err) {
-
console.log(err);
-
}else
-
{
-
-
console.log(connect.test());
-
}
-
});
- console.log('ecec before test');
由执行结果可以看出,执行过程中异步执行并不阻塞后续的任务,所以先打印了exec before test.