node介绍

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);

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,154评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,252评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,107评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,985评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,905评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,256评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,978评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,611评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,891评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,910评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,736评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,516评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,995评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,132评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,447评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,034评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,242评论 2 339

推荐阅读更多精彩内容

  • ​然后得到日本刻板的父亲,把孩子放在锅里蒸汗,无语,想把它们撑死,她们得到了风的帮助着,小屋里峰,为他们提供了一个...
    海哥0001阅读 173评论 0 0
  • 在这一年里,很难统计杀杀君总共听了多少首欧美音乐,不过数字确实不在少数。其中,不乏有不对味的,听上几遍也就从资料库...
    杀杀君阅读 479评论 0 2
  • 姓名:赵丽娟 公司:丛迪服装有限公司 【日精进打卡第82天】 【知~学习】 《六项精进》大纲2遍,共212遍; 《...
    阿诗玛_6209阅读 209评论 0 0
  • 2018年,7月28号早,4.50闹钟准时把我从睡梦中叫醒,起床后的第一件事就是去厕所,肚子隐约有点疼,出了屋门走...
    珍惜爱_08bb阅读 205评论 0 1