node.js入门

网络与IP

HTTP协议的底层是由TCP和IP协议(TCP/IP)构建的

什么是TCP

TCP传输控制协议(Transmission Control Protocol):按层次分,TCP位于传输层,提供可靠的字节流服务。
换句话说,为了更容易的传输大数据,TCP协议会把数据分割成以报文段为单位的数据包进行管理,并且TCP协议能够确认数据最终是否到达对方(一般指所谓的三次握手)。

  1. TCP与UDP的区别:
    简答:TCP 可靠、面向连接、相对 UDP 较慢;UDP 不可靠,不面向连接、相对 TCP 较快。搞定。
  2. TCP的三次握手:
    • 简答:每次建立连接前,客户端和服务端之前都要先进行三次对话才开始正式传输内容,三次对话大概是这样的:
      1. 客户端:我要连接你了,可以吗
      2. 服务端:嗯,我准备好了,连接我吧
      3. 客户端:那我连接你咯。
      4. 开始后面步骤
    • 详细解答:握手过程中使用了TCP的标志(flag)——SYG(synchronize)和ACG(acknowledge)
      1. 发送端:发送一个带SYG标志的数据包给对方
      2. 接收端:收到后,回传一个带SYG/ACK标志的数据包以示传达确认信息
      3. 发送端:收到后,再回传一个带ACK标志的数据包,代表握手结束。

IP网络协议(Internet Protocol)

从层次上分,IP网络协议位于网络层,其作用是把各种数据包传送给对方,为了确保数据传送到正确的对象,则需要满足一些条件,其中最重要的两个便是:IP地址与MAC地址

  • IP地址指明了节点被分配到的地址
  • MAC地址是指的网卡所属的固定地址

注意:
IP是一种网络协议,而IP地址是类似127.0.0.1的地址。
IP地址可以与MAC地址进行匹配。IP地址可换,而MAC地址基本不会变。

在互联网中,一般一个设备对应一个IP地址。通俗理解,IP地址分为内网IP与外网IP


内网与外网
  • 电信服务商提供DNS服务,你从网页中输入的网址首先会去电信查找对应的IP地址。
  • 路由器有一个「内网IP」与一个「外网IP」。
    • 内网中的设备可以互相访问(比如你可以用电脑或手机进入 http://192.168.1.1 来查看你的路由器),但是不能直接访问外网,内网设备想要访问外网,就必须经过路由器中转。
    • 外网中的设备可以互相访问(比如 qq.com 可以把首页发送给你的路由器,你的路由器有外网 IP),但是外网中的设备无法访问你的内网设备。
    • 外网的资源通过路由器的中转传达至内网的各个设备中,路由器在其中充当指路人的角色。
  • 路由器没有固定的「外网IP」,都是临时分配的,类似14.17.32.21,每次路由器重启都会被重新分配一个IP地址。
  • 路由器与其wifi组成整个内网,在内网中的每个设备都有一个对应的「外网IP」,类似192.168.1.1,这个内网IP也不是固定的,一般设备断开wifi重连都会改变内网IP地址。
  • 两个特殊的IP,本地IP 127.0.0.1 代表设备自身,特别的IP 0.0.0.0 不表示任何设备。

端口

端口其实就是一个编号,并不是一种硬件。
一个服务器(硬件)不一定只提供一种服务,比如一个服务器既提供 HTTP 服务,又提供 FTP 服务,还提供 SMTP 服务(邮件服务),那么只用一个 IP 是无法告诉服务器你想要使用哪种服务。

所以这里有一个重要的原则:一个端口对应一个服务。

  • HTTP服务 80端口
  • HTTPS服务 443端口
  • FTP服务 21端口

每个机器一共有65535(2的16次方减一)个端口(协议规定)

  1. 0到1023(2的10次方减一)号端口留给系统使用。
  2. 其他端口用户用
  3. 如果端口被占用,需要停掉该端口的服务才能再次使用。

写一个简易的HTTP Server

创建一个后台服务

任何网络服务应用程序总是要先创建一个服务对象。这在 Node.js 中通常通过 createServer 方法。

var http = require('http');

var server = http.createServer(function(request, response) {
  // magic happens here!
});

每当有 HTTP 请求到达服务器时,createServer 中传入的函数就被自动执行。所以这个函数也被称为是请求处理函数。
当一个 HTTP 到达服务端,node 调用 request 处理程序,并产生一些唾手可得的对象用以处理传输,这些对象就是 request 和 response。。

监听端口

实际上,为了处理请求,listen 方法需要在 server 对象上被显式调用。在大多数情况下,你只要把端口号作为参数传入 listen 方法中,作为监听端口即可。

var port = process.argv[2]//命令的第三个参数

server.listen(port)

请求方法、访问地址以及请求头

当处理一个请求时,第一件事你需要做的是看一下这个方法和其访问地址,以此决定你到底采取何种合理的行为。Node 通过把这些行为属性附加到 request 对象上,使得我们处理起来相对而言可以轻松一些。

var method = request.method
var path = request.url

这里的 method 总是一个普通的 HTTP 方法动作行为 (verb),path 是指没有服务器协议和 端口号的完整访问地址。一个典型的访问地址通常意味着包括第三个斜杠以及后面的所有内容。
请求头也不是很难得到,它们也在 request 对象里,称为 headers。

var headers = request.headers
var userAgent = headers['user-agent']

所有的请求头全是小写字母,而不管实际上它们是怎么进行传输的。所以在无论任何 情况下,解析请求头就得到了简化。
如果一些请求头出现重复,它们的值不是被覆盖,就是通过英文分号进行分割。

设置响应头

响应头通过一个 setHeader 的属性很方便的设置。

response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');

设置响应头时,它们的名字是大小写敏感的。如果你重复设置响应头,最后一次设置的值也就是系统得到的值。

发送响应体

既然 response 对象是一个 WritableStre,向客户端写入返回体只是一个普通的流方法的问题。

response.write('<!DOCTYPE>\n<html>'  + 
      '<head><link rel="stylesheet" href="/style.js">' +
      '</head><body>'  +
      '<h1>你好</h1>' +
      '<script src="/script.html"></script>' +
      '</body></html>')
response.end();

也可以将响应体放在end方法中。

关于错误

请求与响应若是发生错误,则会自动触发自身的error事件。如果你不去处理监听这个事件,此错误将被抛出,这导致你的程序崩溃。 你应该无论如何都要添加 'error' 事件去监听你的请求对象,哪怕你只是做一个日志或者用你自己的独有方式去处理。

request.on('error', function() {
  // This prints the error message and stack trace to `stderr`.
  console.error(err);
});

response.on('error', function() {
  // This prints the error message and stack trace to `stderr`.
  console.error(err);
});

HTTP 状态码

如果你嫌麻烦不想设置它,返回客户端的默认状态码总是 200。当然,不是每个 HTTP 返回码必须都是 200,在某些情况下你一定希望返回一个不同的状态码,所以你应该设置 statusCode 属性。

response.statusCode = 404;

代码示例

var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var path = request.url 
  var query = ''
  if(path.indexOf('?') >= 0){ query = path.substring(path.indexOf('?')) }
  var pathNoQuery = parsedUrl.pathname
  var queryObject = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('HTTP 路径为\n' + path)
  if(path == '/style.js'){
    response.setHeader('Content-Type', 'text/css; charset=utf-8')
    response.write('body{background-color: #ddd;}h1{color: red;}')
    response.end()
  }else if(path == '/script.html'){
    response.setHeader('Content-Type', 'text/javascript; charset=utf-8')
    response.write('alert("这是JS执行的")')
    response.end()
  }else if(path == '/index.css'){
    response.setHeader('Content-Type', 'text/html; charset=utf-8')
    response.write('<!DOCTYPE>\n<html>'  + 
      '<head><link rel="stylesheet" href="/style.js">' +
      '</head><body>'  +
      '<h1>你好</h1>' +
      '<script src="/script.html"></script>' +
      '</body></html>')
    response.end()
  }else{
    response.statusCode = 404
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)

以上内容参考node官网,感兴趣的可以去看看。

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

推荐阅读更多精彩内容

  • 名词延伸 通俗的说,域名就相当于一个家庭的门牌号码,别人通过这个号码可以很容易的找到你。如果把IP地址比作一间房子...
    杨大虾阅读 20,604评论 2 57
  • 1、TCP为什么需要3次握手,4次断开? “三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端...
    杰伦哎呦哎呦阅读 3,484评论 0 6
  • 1.这篇文章不是本人原创的,只是个人为了对这部分知识做一个整理和系统的输出而编辑成的,在此郑重地向本文所引用文章的...
    SOMCENT阅读 13,071评论 6 174
  • 文章首发于个人blog欢迎指正补充,可联系lionsom_lin@qq.com原文地址:《网络是怎样连接的》阅读整...
    lionsom_lin阅读 14,156评论 6 31
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,058评论 0 8