打造一個屬於本身的server

什麼是server

在開始打造本身的服務器以前,咱們首先明確一下服務器的定義:一個管理資源併爲用戶提供服務的計算機軟件。css

根據功能服務器分爲兩類

  • static web server,例如常見的nginx apache等等
  • dynamic web server,例如常見的tomcat,jboss,resin等等

動靜態服務器區別

對於靜態服務器來講通常就是讀取資源而後返回給browser;動態服務器意味着返回給browser的文件是通過邏輯處理動態產生的。html

服務器具備的功能特性

  • nginx,tomcat這個兩個以前用過,也研究過,因此拿這兩個舉一下示例,不過如今不多用了,如今基本上都是使用node相關的,因此最後構建的serve會基於node。

nginx

nginx特色

  • 配置簡單,靈活(只有一個主配置文件nginx.conf)
  • 支持高併發(靜態小文件)
  • 佔用資源相對較少(2w併發,開啓10個線程,內存消耗只有幾百M)
  • 功能種類多(例如proxy,cache,Log,Gzip等等)

nginx應用場景

靜態服務器(圖片,js,css等等)

server {
        listen       8080;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }
}

說明 上面是nginx配置,指定訪問根目錄和默認主頁,以及監聽端口java

➜  ~ clear
➜  ~ curl -i  http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.12.2 //服務器類型和版本
Date: Fri, 02 Mar 2018 08:49:44 GMT
Content-Type: text/html
Content-Length: 11
Last-Modified: Fri, 02 Mar 2018 08:46:27 GMT //支持Last-Modified緩存機制
Connection: keep-alive //支持持久鏈接
ETag: "5a990f63-b"  //支持ETag緩存機制
Accept-Ranges: bytes // 支持斷點續傳

hello  jsdt% //響應體

說明 上面是本地測試請求,從響應頭中能夠看到支持不少功能node

反向代理,負載均衡

jsdt-server-demo
說明 上面是試驗效果nginx

upstream  jsdt.com {  
          server    127.0.0.1:8083  max_fails=3 fail_timeout=30s weight=1;
          server    47.97.xxx.xxx:8084  max_fails=3 fail_timeout=30s  weight=2;  //爲了安全 隱藏真實ip地址
      } 
    server {
        listen       8080;
        server_name  localhost; 

        location / {
            root   html;
           # index  index.html index.htm;
            proxy_pass http://jsdt.com;  
            proxy_redirect default;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }}

說明 上面我摘取了關鍵的部分配置,採用了輪訓+weight算法,其它還有ip_hash、url_hash等算法。真實的應用狀況,還須要考慮不少問題,例如集羣的session同步,記得大學實習期間,當時公司用的是cookie+memcache集羣的方案。git

tomcat

tomcat特色

tomcat運行在jvm上,跨平臺,是一個Servlet容器(能夠運行Servlet,編譯jsp),實現了在http請求響應處理中所須要的http接口相關實現類。除此以外也支持虛擬主機,session共享,靜態文件處理等等,只不過沒那麼專業而已。

tomcat應用場景

tomcat-jsdt
說明 如上所示,咱們能夠在頁面中添加動態的處理邏輯,返回的數據根據用戶可定製化(相比靜態服務器優勢),最終.jsp被tomcat編譯爲.java,而後被javac編譯爲通用字節碼文件,最終運行在jvm上。github

如何實現一個本身的服務器

在實現本身的服務器以前,首先咱們明確一下server的本質,server屬於應用層的協議,基於tcp的封裝, 而tcp的應用實現是基於socket(不管是node,仍是java都有socket)的封裝。
socket監聽某個端口,獲取面向流的數據data,咱們的server所要作的就是對data進行解析封裝,以使其符合http的規範。

接下來實現本身的靜態server

由於有http模塊,因此node當中實現一個基礎server很簡單。可是若是附加額外的功能,例如壓縮,緩存,斷點續傳,反向代理什麼的就須要本身添加了。
接下來首先看一下項目結構,bin目錄主要是放啓動腳本相關的,主邏輯在app.js中,而後根據功能將代碼拆分紅不一樣的模塊。templatet目錄放置編譯的原始模板。web

|____bin
| |____.DS_Store
| |____deamon.js
| |____start
| |____yargsConfig.js
|____node_modules
|____package-lock.json
|____package.json
|____readme.md
|____src
| |____.DS_Store
| |____app.js
| |____asset
| |____cacheSupport.js
| |____config.js
| |____picGuard.js
| |____template
| |____util.js

在server運行前,首先咱們經過yargs模塊獲取解析好的命令行參數。以下所示算法

if(argv.D){
    let sp = cp.spawn(process.execPath, ['deamon.js'],{
        cwd: __dirname,
        stdio: ['ignore','ignore','ignore'],
        env: argv,
        detached: true  //http://nodejs.cn/api/child_process.html#child_process_child_process_spawn_command_args_options
    } )
    sp.unref()
} else {
    let config = Object.assign({}, defautConfig, argv)
    let server = new Server(config);
    server.start();
    console.log('server already started')
}

說明 若是開啓deamon模式,則經過子進程的方式讓服務在後臺運行,反之則直接啓動server實例apache

在啓動server以後,開始接受並處理請求,下面以斷點續傳功能模塊做爲示例

function byteRangeStream(req, res, filepath, statObj) {
    let start = 0
    let end = statObj.size-1
    let range = req.headers['range']
    if (range){
        res.setHeader('Accept-Range','bytes')
        res.statusCode = 206 //a part of content
        let result = range.match(/bytes=(\d*)-(\d*)/);
        if (result) {
            start = isNaN(result[1]) ? start : parseInt(result[1]);
            end = isNaN(result[2]) ? end : parseInt(result[2]) - 1;
        }
    }
    return fs.createReadStream(filepath,{
        start,
        end
    })
}
module.exports ={
    byteRangeStream
}

說明 在主模塊app.js中,導入上述模塊,如代碼中所示首先判斷客戶端是否支持斷點續傳,依據range請求頭,若是有請求範圍,直接返回請求範圍內的數據,不然所有讀取返回,靠的是browser和server的協商機制,須要雙方都支持才能完成整個過程。
更多功能模塊能夠參考個人github, 歡迎star。

總結

寫這篇文章,總結了下server的相關知識,參考了以前大學時作的筆記,看到以前作的記錄,回憶當時在學校學習和公司實習的經歷,感慨萬千。時光易逝,作好當下的本身。

相關文章
相關標籤/搜索