美文网首页
node介绍

node介绍

作者: wish_dd | 来源:发表于2018-11-24 10:16 被阅读0次

    node 特点

    • 单线程
      传统的java是为每个连接建一个线程,每个线程需要耗费大约2MB内存。如果需要处理大量的并发就需要大量的机器。而node只是有一个线程,当有客户端连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。
    • 非阻塞I/O
      理论上单线程处理,在执行I/O操作时,整个线程会挂起,阻塞,等到结果返回后,才能执行后面的代码,而在node中I/O是非 阻塞的,当执行I/O时,只是把I/O丢给libuv处理,继续执行后面的代码,当某个I/O执行完毕时,将以事件的形式通知node线程,线程执行这个事件的回调函数。
    • 事件驱动
      客户端请求建立连接,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件循环”。

    创建一个Server

    'use strict';
    const http = require('http');
    http.createServer(function(req, res){
        res.writeHead(200, {'Content-Type':'text/html; charset= UTF-8; '});
        res.end('Hello World!');
    }).listen(8080);
    
    ➜  ~ curl 127.0.0.1:8080
    Hello World!%
    

    这就是一个最简单的helloWorld,那我们客户端请求到server是如何运行的呢?

    1.http模块在node 中http模块有2个一个是http-client,一个是http-server
    2.http模块是继承与net模块,net模块是继承与events
    3.events只提供了 events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装
    4.此时的http就拥有了事件的监听与触发功能

    实现原理

    我们通过代码http.createServer方法

    // http.js
    function createServer(opts, requestListener) {
      return new Server(opts, requestListener);
    }
    //http-server.js
    function Server(options, requestListener) {
        /*省略代码*/
      if (requestListener) {
        this.on('request', requestListener);  
      }
      this.on('connection', connectionListener);
    }
    
    核心代码是注册了2个方法一个request,一个connection方法
    

    connection 方法是在tcp的3次握手会被调用,在client-server建立连接成功之后,

    function connectionListenerInternal(server, socket) {
      debug('SERVER new http connection');
    /**省略代码**/
      parser.onIncoming = parserOnIncoming.bind(undefined, server, socket, state);
    
      // We are consuming socket, so it won't get any actual data
      socket.on('resume', onSocketResume);
      socket.on('pause', onSocketPause);
    
      // Override on to unconsume on `data`, `readable` listeners
      socket.on = socketOnWrap;
    
      // We only consume the socket if it has never been consumed before.
      if (socket._handle) {
        var external = socket._handle._externalStream;
        if (!socket._handle._consumed && external) {
          parser._consumed = true;
          socket._handle._consumed = true;
          parser.consume(external);
        }
      }
      parser[kOnExecute] =
        onParserExecute.bind(undefined, server, socket, parser, state);
    
      socket._paused = false;
    }
    

    tcp建立成功,然后server就需要解析数据,生成一个req与res,同时要emit触发request方法,这样就回到了我们的http.createServer(callback)方法

    function parserOnIncoming(server, socket, state, req, keepAlive) {
      resetSocketTimeout(server, socket, state);
    
      if (req.upgrade) {
        req.upgrade = req.method === 'CONNECT' ||
                      server.listenerCount('upgrade') > 0;
        if (req.upgrade)
          return 2;
      }
    
      state.incoming.push(req);
    
      // If the writable end isn't consuming, then stop reading
      // so that we don't become overwhelmed by a flood of
      // pipelined requests that may never be resolved.
      if (!socket._paused) {
        var ws = socket._writableState;
        if (ws.needDrain || state.outgoingData >= socket.writableHighWaterMark) {
          socket._paused = true;
          // We also need to pause the parser, but don't do that until after
          // the call to execute, because we may still be processing the last
          // chunk.
          socket.pause();
        }
      }
    
      var res = new server[kServerResponse](req);
      res._onPendingData = updateOutgoingData.bind(undefined, socket, state);
    
      res.shouldKeepAlive = keepAlive;
      DTRACE_HTTP_SERVER_REQUEST(req, socket);
      COUNTER_HTTP_SERVER_REQUEST();
    
      if (socket._httpMessage) {
        // There are already pending outgoing res, append.
        state.outgoing.push(res);
      } else {
        res.assignSocket(socket);
      }
    
      // When we're finished writing the response, check if this is the last
      // response, if so destroy the socket.
      res.on('finish',
             resOnFinish.bind(undefined, req, res, socket, state, server));
    
      if (req.headers.expect !== undefined &&
          (req.httpVersionMajor === 1 && req.httpVersionMinor === 1)) {
        if (continueExpression.test(req.headers.expect)) {
          res._expect_continue = true;
    
          if (server.listenerCount('checkContinue') > 0) {
            server.emit('checkContinue', req, res);
          } else {
            res.writeContinue();
            server.emit('request', req, res);
          }
        } else if (server.listenerCount('checkExpectation') > 0) {
          server.emit('checkExpectation', req, res);
        } else {
          res.writeHead(417);
          res.end();
        }
      } else {
        server.emit('request', req, res);
      }
      return 0;  // No special treatment.
    }
    关键代码 server.emit('request', req, res);
    

    这样我们就监听到了客户端的请求。

    相关文章

      网友评论

          本文标题:node介绍

          本文链接:https://www.haomeiwen.com/subject/ltcdqqtx.html