Web服务器20190530

自己写一个Web服务器

  • 在此之前需要先了解一些东西。

一、网络与IP

HTTP 协议的底层其实是由 TCP 协议和 IP 协议(简称 TCP/IP)构建的。

TCP传输控制协议(Transmission Control Protocol)
TCP协议的特点是:
面向连接、点对点(一对一)、可靠交付、面向字节流,也就是说仅仅把上层协议传递过来的数据当成字节传输。
为了实现TCP上述的特点,TCP协议需要解决的是面向连接(建立连接和关闭连接的方式)、可靠传输(错误确认和重传)、流量控制(发送方和接收方的传输速率协调)、拥塞控制四个方面。
IP网络协议(Internet Protocol)
只要你在互联网中,那么你就会有一个 IP。通俗上理解,IP 分为「内网 IP」和「外网 IP」

  • 什么是外网IP?
    例如,你买了一个路由器,只要路由器连接上了电信的服务器,那么路由器就会有一个「外网 IP」,比如「14.17.32.211」就是一个外网 IP。这就是你在互联网中的地址。
  • 什么是内网IP?
    答案就是你的电脑和手机的IP,路由器会在你家里创建一个内网,内网中的设备使用内网 IP,一般来说这个 IP 的格式都是 192.168.xxx.xxx。
    一般路由会给自己分配一个好记的内网 IP,如 192.168.1.1
    然后路由会给每一个内网中的设备分配一个不同的内网 IP,如电脑是 192.168.1.2,手机是 192.168.1.3,以此类推。
    现在路由器有两个 IP,一个外网 IP(14.17.32.211)和一个内网 IP(192.168.1.1)
    内网中的设备可以互相访问(比如你可以用电脑或手机进入 http://192.168.1.1 来查看你的路由器),但是不能直接访问外网,内网设备想要访问外网,就必须经过路由器中转。外网中的设备也是这样。

二、端口

  • 你想要访问一个设备,只指定IP是不够的,还必须在指定端口。
  • 端口其实就是一个编号,并不是一种硬件。一个服务器(硬件)不一定只提供一种服务,比如一个服务器既提供 HTTP 服务,又提供 FTP 服务,还提供 SMTP 服务(邮件服务),那么只用一个 IP 是无法告诉服务器你想要使用哪种服务。
    所以这里有一个重要的原则:一个端口对应一个服务。
    问题一:我怎么知道应该使用什么端口?
    答:维基百科可以告诉你,点进去看看吧。
    问题二:一共由多少端口?
    答:每个机器一共有 65535(2的16次方减1)个端口(这是协议规定的)。
    不过这些端口的使用由一些规定:
    1、 0 到 1023(2的10次方减1)号端口是留给系统使用的,你只有拥有了管理员权限后,才能使用这 1024 个端口。
    2、其他端口可以给普通用户使用。
    3、如果一个端口正在提供服务,也就是被占用了,那么就不能再使用这个端口。除非你先停掉正在占用这个端口的服务。以后你们会经常遇到这个问题。
    问题三:我访问 http://qq.com 时并没有提供端口号,为什么我依然可以访问?
    答:因为浏览器帮你加了默认端口号 80。

三、一个简易Server

1、服务器你已经有了,你使用的电脑就是你的服务器。
2、但是你还没有提供 HTTP 服务的「程序」,用脚本就可以提供 HTTP 服务,例如Node.js脚本。

Node.js服务器

  1. 新建一个安全的目录
    cd ~/Desktop
    mkdir node-demo
    cd node-demo
  2. touch server.js
  3. 编辑 server.js,内容如下:
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)
  console.log('查询字符串为\n' + query)
  console.log('不含查询字符串的路径为\n' + pathNoQuery)



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

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

4.运行node server.js
5.根据报错提示调整你的命令
6.成功之后,这个 server 会保持运行,无法退出

  • 如果你想「中断」这个 server,按 Ctrl C即可(C 就是 Cancel 的意思)
  • 中断后你才能输入其他命令
  • 建议把这个 server 放在那里别动,新开一个 Bash 窗口,完成下面的教程好了服务器完成。

7.这个服务器目前只有一个功能,那就是打印出路径和查询字符串。
8.在新的 Bash 窗口运行 curl http://localhost:你的指定的端口/xxx 或者 curl http://127.0.0.1:你指定的端口/xxx。你会马上发现 server 打印出了路径:

图片.png

9.这说明我们的 server 收到了我们用 curl 发出的请求

10.由于 server 迟迟没有发出响应,所以 curl 就一直等在那里,无法退出(用 Ctrl+C中断 curl)
发出响应
接下来让我们的server 发出响应
1.编辑 server.js
2.在中间标注的区域添加两行代码
response.write('Hi')
response.end()
3.中断之前的 server,重新运行 node server.js 8888
4.curl http://127.0.0.1:8888/xxx,结果如下:
Hi%
(这里注意,Windows系统可能有不一样的结果,例如下图,原因我暂未知

图片.png

这个 % 不是我们的内容,% 表示结尾。如果你不喜欢 % ,就把 'Hi' 换成 'Hi\n'。
5.好了,响应添加成功
6.使用 curl -s -v -- "http://localhost:8888/xxx" 可以查看完整的请求和响应。

下面是一个完整的例子:

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容