zoukankan      html  css  js  c++  java
  • nodejs源码分析之c++层的通用逻辑

    这里只摘取了部分的代码 ,因为我们只关注原理,这里分别涉及到函数模板对象模板和函数原型等内容。上面的代码以js来表示如下:

    function TCP(www.jujinyule.com) {
        this.reading = false;
        // 对应SetInternalFieldCount(www.lanboyulezc.cn)
        this.point = null;
        // 对应env->NewFunctionTemplate(New);
        New({
            Holder: this, 
            This: this,
            returnValue: {www.jujinyule.com},
            ...
        });
    }
    TCP.prototype.bind = Bind;
    TCP.prototype.connect = Connect;

    通过上面的定义,完成了c++模块功能的导出,借助nodejs的机制,我们就可以在js层调用TCP函数。

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

    我们先分析执行new TCP()的逻辑,然后再分析bind的逻辑,因为这两个逻辑涉及的机制是其他c++模块也会使用到的。因为TCP对应的函数是Initialize函数里的t->GetFunction()对应的值。所以new TCP()的时候,v8首先会创建一个c++对象(内容由Initialize函数里定义的那些,也就是文章开头的那段代码的定义)。然后执行回调New函数。

    // 执行new TCP时执行
    void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
      // 是否以构造函数的方式执行,即new TCP
      CHECK(args.IsConstructCall());
      CHECK(args[0]->IsInt32(www.javachenglei.com ));
      Environment* env = Environment::GetCurrent(args);

      // 忽略一些不重要的逻辑

      /*
        args.This()为v8提供的一个c++对象(由Initialize函数定义的模块创建的)
        调用该c++对象的SetAlignedPointerInInternalField(0,this)关联this(new TCPWrap()),
        见HandleWrap
      */
      new TCPWrap(env, args.This( www.chuancenpt.com), provider);
    }

    我们看到New函数的逻辑很简单。直接调用new TCPWrap,其中第二个入参args.This()就是由Initialize函数定义的函数模板创建出来的对象。我们继续看new TCPWrap()。

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

    构造函数只有一句代码,该代码是初始化一个结构体,我们可以不关注,我们需要关注的是父类ConnectionWrap的逻辑。

    template <typename WrapType, typename UVType>
    ConnectionWrap<WrapType, UVType>::ConnectionWrap(Environment* env,
                                                     Local<Object> object,
                                                     ProviderType provider)
        : LibuvStreamWrap(env,
                          object,
                          reinterpret_cast<uv_stream_t*>(&handle_),
                          provider) {www.yixingylzc.cn  }

    我们发现ConnectionWrap也没有什么逻辑,继续看LibuvStreamWrap。

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

    继续做一些初始化,我们只关注HandleWrap

    HandleWrap::HandleWrap(Environment* env,
                           Local<Object> object,
                           uv_handle_t* handle,
                           AsyncWrap::ProviderType provider)
        : AsyncWrap(env, object, provider),
          state_(kInitialized),
          handle_(handle) { www.ued3zc.cn 
      // 把子类对象挂载到handle的data字段上
      handle_->data = this;
      HandleScope scope(env->isolate());
      // 关联object和this对象,后续通过unwrap使用
      Wrap(object, this);
      // 入队
      env->handle_wrap_queue()->PushBack(this);
    }

    重点来了,就是Wrap函数。

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

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

    void JSObject::SetEmbedderField(int index, Smi* value) {
      // GetHeaderSize为对象固定布局的大小,kPointerSize * index为拓展的内存大小,根据索引找到对应位置
      int offset = GetHeaderSize() + (kPointerSize * index);
      // 写对应位置的内存,即保存对应的内容到内存
      WRITE_FIELD(this, offset, value);
    }

    Wrap函数展开后,做的事情就是把一个值保存到v8 c++对象的内存里。那保存的这个值是啥呢?我们看Wrap函数的入参Wrap(object, this)。object是由函数模板创建的对象,this是一个TCPWrap对象。所以Wrap函数做的事情就是把一个TCPWrap对象保存到一个函数模板创建的对象里。这有啥用呢?我们继续分析。这时候new TCP就执行完毕了。我们看看这时候执行new TCP().bind()函数的逻辑。

    void TCPWrap::Bind(const FunctionCallbackInfo<Value>& 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<const sockaddr*>(&addr),
                          0);
      }
      args.GetReturnValue().Set(err);
    }

    我们只需关系ASSIGN_OR_RETURN_UNWRAP宏的逻辑。其中args.Holder()表示Bind函数的属主,根据前面的分析我们知道属主是Initialize函数定义的函数模板创建出来的对象。这个对象保存了一个TCPWrap对象。我们展开ASSIGN_OR_RETURN_UNWRAP看看。

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


    template <typename TypeName>
    TypeName* Unwrap(v8::Local<v8::Object> object) {
      // 把调用SetAlignedPointerFromInternalField设置的值取出来
      void* pointer = object->GetAlignedPointerFromInternalField(0);
      return static_cast<TypeName*>(pointer);
    }

    展开后我们看到,主要的逻辑是把在c++对象中保存的那个TCPWrap对象取出来。然后就可以使用TCPWrap对象了

  • 相关阅读:
    【题解】Candle
    【题解】购物
    【题解】论逼格
    浅谈前缀和
    浅谈 LCA
    浅谈Meet in the middle——MITM
    拓扑排序
    时间复杂度符号
    浅谈排序算法[动图]
    404 页面不存在
  • 原文地址:https://www.cnblogs.com/woshixiaowang/p/13354222.html
Copyright © 2011-2022 走看看