真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

nodejs源碼分析中c++層的通用邏輯是什么

這篇文章主要講解了“nodejs源碼分析中c++層的通用邏輯是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“nodejs源碼分析中c++層的通用邏輯是什么”吧!

在肅南裕固族自治等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷推廣,外貿(mào)網(wǎng)站制作,肅南裕固族自治網(wǎng)站建設(shè)費(fèi)用合理。

我們知道nodejs分為js、c++、c三層,本文以tcp_wrap.cc為例子分析c++層實(shí)現(xiàn)的一些通用邏輯。nodejs的js和c++通信原理q.com/s?__biz=MzUyNDE2OTAwNw==&mid=2247484815&idx=1&sn=525d9909c35eabf3c728b303d27061df&chksm=fa303fcfcd47b6d9604298d0996414a5e16c798c1a2dab4e01989bb41ba9c5372ebc00ca0943&token=162783191&lang=zh_CN#rd)之前已經(jīng)分析過,所以直接從tcp模塊導(dǎo)出的功能開始分析(Initialize函數(shù))。

void TCPWrap::Initialize(Local target,
                         Local unused,
                         Local context) {
                         Environment* env = Environment::GetCurrent(context);
  /*
    new TCP時(shí),v8會(huì)新建一個(gè)c++對(duì)象(根據(jù)InstanceTemplate()模板創(chuàng)建的對(duì)象),然后傳進(jìn)New函數(shù),
    然后執(zhí)行New函數(shù),New函數(shù)的入?yún)rgs的args.This()就是該c++對(duì)象
  */
  // 新建一個(gè)函數(shù)模板
  Local t = env->NewFunctionTemplate(New);
  // 設(shè)置函數(shù)名稱
  Local tcpString = FIXED_ONE_BYTE_STRING(env->isolate(), "TCP");
  t->SetClassName(tcpString);
  /*
      ObjectTemplateInfo對(duì)象的kDataOffset偏移保存了這個(gè)字段的值,
      用于聲明ObjectTemplateInfo創(chuàng)建的對(duì)象額外申請(qǐng)的內(nèi)存大小
  */
  t->InstanceTemplate()->SetInternalFieldCount(1);

  // 設(shè)置對(duì)象模板創(chuàng)建的對(duì)象的屬性。ObjectTemplateInfo對(duì)象的kPropertyListOffset偏移保存了下面這些值
  t->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "reading"),
                               Boolean::New(env->isolate(), false));

  // 在t的原型上增加屬性
  env->SetProtoMethod(t, "bind", Bind);
  env->SetProtoMethod(t, "connect", Connect);
  // 在target中注冊(cè)該函數(shù)
  target->Set(tcpString, t->GetFunction());
 

這里只摘取了部分的代碼 ,因?yàn)槲覀冎魂P(guān)注原理,這里分別涉及到函數(shù)模板對(duì)象模板和函數(shù)原型等內(nèi)容。上面的代碼以js來表示如下:

function TCP() {
    this.reading = false;
    // 對(duì)應(yīng)SetInternalFieldCount(1)
    this.point = null;
    // 對(duì)應(yīng)env->NewFunctionTemplate(New);
    New({
        Holder: this, 
        This: this,
        returnValue: {},
        ...
    });
}
TCP.prototype.bind = Bind;
TCP.prototype.connect = Connect;
 

通過上面的定義,完成了c++模塊功能的導(dǎo)出,借助nodejs的機(jī)制,我們就可以在js層調(diào)用TCP函數(shù)。

const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const instance = new TCP(...);
instance.bind(...);
 

我們先分析執(zhí)行new TCP()的邏輯,然后再分析bind的邏輯,因?yàn)檫@兩個(gè)邏輯涉及的機(jī)制是其他c++模塊也會(huì)使用到的。因?yàn)門CP對(duì)應(yīng)的函數(shù)是Initialize函數(shù)里的t->GetFunction()對(duì)應(yīng)的值。所以new TCP()的時(shí)候,v8首先會(huì)創(chuàng)建一個(gè)c++對(duì)象(內(nèi)容由Initialize函數(shù)里定義的那些,也就是文章開頭的那段代碼的定義)。然后執(zhí)行回調(diào)New函數(shù)。

// 執(zhí)行new TCP時(shí)執(zhí)行
void TCPWrap::New(const FunctionCallbackInfo& args) {
  // 是否以構(gòu)造函數(shù)的方式執(zhí)行,即new TCP
  CHECK(args.IsConstructCall());
  CHECK(args[0]->IsInt32());
  Environment* env = Environment::GetCurrent(args);

  // 忽略一些不重要的邏輯

  /*
    args.This()為v8提供的一個(gè)c++對(duì)象(由Initialize函數(shù)定義的模塊創(chuàng)建的)
    調(diào)用該c++對(duì)象的SetAlignedPointerInInternalField(0,this)關(guān)聯(lián)this(new TCPWrap()),
    見HandleWrap
  */
  new TCPWrap(env, args.This(), provider);
}
 

我們看到New函數(shù)的邏輯很簡(jiǎn)單。直接調(diào)用new TCPWrap,其中第二個(gè)入?yún)rgs.This()就是由Initialize函數(shù)定義的函數(shù)模板創(chuàng)建出來的對(duì)象。我們繼續(xù)看new TCPWrap()。

TCPWrap::TCPWrap(Environment* env, 
                Local object, 
                ProviderType provider)
    : ConnectionWrap(env, object, provider) {
  int r = uv_tcp_init(env->event_loop(), &handle_);
}
 

構(gòu)造函數(shù)只有一句代碼,該代碼是初始化一個(gè)結(jié)構(gòu)體,我們可以不關(guān)注,我們需要關(guān)注的是父類ConnectionWrap的邏輯。

template 
ConnectionWrap::ConnectionWrap(Environment* env,
                                                 Local object,
                                                 ProviderType provider)
    : LibuvStreamWrap(env,
                      object,
                      reinterpret_cast(&handle_),
                      provider) {}
 

我們發(fā)現(xiàn)ConnectionWrap也沒有什么邏輯,繼續(xù)看LibuvStreamWrap。

LibuvStreamWrap::LibuvStreamWrap(Environment* env,
                                 Local object,
                                 uv_stream_t* stream,
                                 AsyncWrap::ProviderType provider)
    : HandleWrap(env,
                 object,
                 reinterpret_cast(stream),
                 provider),
      StreamBase(env),
      stream_(stream) {
}
 

繼續(xù)做一些初始化,我們只關(guān)注HandleWrap

HandleWrap::HandleWrap(Environment* env,
                       Local object,
                       uv_handle_t* handle,
                       AsyncWrap::ProviderType provider)
    : AsyncWrap(env, object, provider),
      state_(kInitialized),
      handle_(handle) {
  // 把子類對(duì)象掛載到handle的data字段上
  handle_->data = this;
  HandleScope scope(env->isolate());
  // 關(guān)聯(lián)object和this對(duì)象,后續(xù)通過unwrap使用
  Wrap(object, this);
  // 入隊(duì)
  env->handle_wrap_queue()->PushBack(this);
}
 

重點(diǎn)來了,就是Wrap函數(shù)。

template 
void Wrap(v8::Local object, TypeName* pointer) {
  object->SetAlignedPointerInInternalField(0, pointer);
}

void v8::Object::SetAlignedPointerInInternalField(int index, void* value) {
  i::Handle obj = Utils::OpenHandle(this);
  i::Handle::cast(obj)->SetEmbedderField(
      index, EncodeAlignedAsSmi(value, location));
}

void JSObject::SetEmbedderField(int index, Smi* value) {
  // GetHeaderSize為對(duì)象固定布局的大小,kPointerSize * index為拓展的內(nèi)存大小,根據(jù)索引找到對(duì)應(yīng)位置
  int offset = GetHeaderSize() + (kPointerSize * index);
  // 寫對(duì)應(yīng)位置的內(nèi)存,即保存對(duì)應(yīng)的內(nèi)容到內(nèi)存
  WRITE_FIELD(this, offset, value);
}
 

Wrap函數(shù)展開后,做的事情就是把一個(gè)值保存到v8 c++對(duì)象的內(nèi)存里。那保存的這個(gè)值是啥呢?我們看Wrap函數(shù)的入?yún)rap(object, this)。object是由函數(shù)模板創(chuàng)建的對(duì)象,this是一個(gè)TCPWrap對(duì)象。所以Wrap函數(shù)做的事情就是把一個(gè)TCPWrap對(duì)象保存到一個(gè)函數(shù)模板創(chuàng)建的對(duì)象里。這有啥用呢?我們繼續(xù)分析。這時(shí)候new TCP就執(zhí)行完畢了。我們看看這時(shí)候執(zhí)行new TCP().bind()函數(shù)的邏輯。

void TCPWrap::Bind(const FunctionCallbackInfo& args) {
  TCPWrap* wrap;
  // 解包處理
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
                          args.Holder(),
                          args.GetReturnValue().Set(UV_EBADF));
  node::Utf8Value ip_address(args.GetIsolate(), args[0]);
  int port = args[1]->Int32Value();
  sockaddr_in addr;
  int err = uv_ip4_addr(*ip_address, port, &addr);
  if (err == 0) {
    err = uv_tcp_bind(&wrap->handle_,
                      reinterpret_cast(&addr),
                      0);
  }
  args.GetReturnValue().Set(err);
}
 

我們只需關(guān)系A(chǔ)SSIGN_OR_RETURN_UNWRAP宏的邏輯。其中args.Holder()表示Bind函數(shù)的屬主,根據(jù)前面的分析我們知道屬主是Initialize函數(shù)定義的函數(shù)模板創(chuàng)建出來的對(duì)象。這個(gè)對(duì)象保存了一個(gè)TCPWrap對(duì)象。我們展開ASSIGN_OR_RETURN_UNWRAP看看。

#define ASSIGN_OR_RETURN_UNWRAP(ptr, obj, ...)                                \
  do {                                                                        \
    *ptr =                                                                    \
        Unwrap::type>(obj);  \
    if (*ptr == nullptr)                                                      \
      return __VA_ARGS__;                                                     \
  } while (0)


template 
TypeName* Unwrap(v8::Local object) {
  // 把調(diào)用SetAlignedPointerFromInternalField設(shè)置的值取出來
  void* pointer = object->GetAlignedPointerFromInternalField(0);
  return static_cast(pointer);
}

展開后我們看到,主要的邏輯是把在c++對(duì)象中保存的那個(gè)TCPWrap對(duì)象取出來。然后就可以使用TCPWrap對(duì)象了。

感謝各位的閱讀,以上就是“nodejs源碼分析中c++層的通用邏輯是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)nodejs源碼分析中c++層的通用邏輯是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!


新聞標(biāo)題:nodejs源碼分析中c++層的通用邏輯是什么
新聞來源:http://weahome.cn/article/pccech.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部