偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

使用Node.js作為完整的云環(huán)境開發(fā)堆棧

開發(fā) 前端
Node.js 并非與 JavaScript 抗衡,而是使用它作為完整的開發(fā)堆棧,從服務器端代碼一直延伸到瀏覽器。Node.js 還充分利用了另一種創(chuàng)新思想:通過回調利用異步 I/O 的并發(fā)性模型。

隨著技術創(chuàng)新表面上繼續(xù)以指數級速度發(fā)展,新思想層出不窮。服務器端的 JavaScript 就是這些新思想之一。 Node.js 是一種事件驅動的 I/O 框架,用于 UNIX 類平臺上的 V8 JavaScript 引擎,適合于編寫可伸縮的網絡程序,如 Web 服務器。 Node.js 正是這種新思想的實現。

51CTO推薦專題:Node.js專區(qū)

Node.js 并非與 JavaScript 抗衡,而是使用它作為完整的開發(fā)堆棧,從服務器端代碼一直延伸到瀏覽器。Node.js 還充分利用了另一種創(chuàng)新思想:通過回調利用異步 I/O 的并發(fā)性模型。

Node.js 云計算平臺

在云計算環(huán)境中使用 Node.js 框架時,能顯示出它的一個巨大優(yōu)點。對于應用程序開發(fā)人員,這往往歸結使用平臺即服務 (PaaS) 或基礎架構即服務 (IaaS) 模型。對于開發(fā)人員而言,最抽象和公認最方便的方法是使用 PaaS 提供程序。圖 1 十分簡單地說明了 PaaS 和IaaS 模型的結構。

圖 1. PaaS 與 IaaS 結構

最近,一個激動人心的開源項目 Cloud Foundry 公布了代碼以創(chuàng)建一個能夠運行 Node.js的私有 PaaS。同樣的主機引擎也可用在公共云和商業(yè)云中,而且它們接受軟件補丁。

基礎架構管理是一大痛點,如果能夠將這項工作外包(永遠!)給規(guī)模經營的提供商,且無論是源代碼,還是物理硬件資源,對于開發(fā)人員確實是一個激動人心的時刻。

使用 Node.js shell

在我們著手編寫一個完整的 Node.js 例子之前,讓我們先開始介紹如何使用交互式 shell。如果尚未安裝 Node.js,您可以參考資源部分,然后按照說明安裝它,或者使用在線的交互式 Node.js 站點之一,它允許您直接在瀏覽器中輸入代碼。

要在 Node.js 中以交互方式編寫 JavaScript 函數,在命令行提示中輸入node,如下所示:

  1. lion% node   
  2. > var foo = {bar: ‘baz’};   
  3. > console.log(foo);   
  4. { bar: ‘baz’ }   
  5. > 

在這個例子中,創(chuàng)建了對象foo,然后調用console.log 將它輸出到控制臺。這十分有效而且有趣,不過當您使用 tab 完成功能來探討 foo 時,如下面的例子所示,真正的樂趣才剛剛開始。如果輸入 foo.bar.,然后按下 tab 鍵,您將看到對象上的可用方法。

  1. > foo.bar.   
  2. [...output suppressed for space...]   
  3. foo.bar.toUpperCase foo.bar.trim   
  4. foo.bar.trimLeft foo.bar.trimRight 

試用 toUpperCase 方法似乎很有趣,下面顯示了它的用法:

  1. > foo.bar.toUpperCase();   
  2.  ‘BAZ’ 

您可以看到,該方法將字符串轉換為大寫字母。這類交互式開發(fā)非常適合于使用像 Node.js這樣的事件驅動型框架進行開發(fā)。

在完成簡單介紹之后,我們開始真正地構建一些東西。

用 Node.js 構建聊天服務器

Node.js 讓編寫基于事件的網絡服務器變得十分簡單。例如,讓我們創(chuàng)建一些聊天服務器。***個服務器十分簡單,幾乎沒有什么功能,也沒有任何異常處理。

一個聊天服務器允許多個客戶端連接到它。每個客戶端都可以編寫消息,然后廣播給所有其他用戶。下面給出了最簡單的聊天服務器的代碼。

  1. net = require(‘net’);   
  2. var sockets = [];   
  3. var s = net.Server(function(socket) {   
  4. sockets.push(socket);   
  5. socket.on(‘data’, function(d) {   
  6. for (var i=0; i < sockets.length; i++ ) {   
  7. sockets[i].write(d);   
  8. }   
  9. });   
  10. });   
  11. s.listen(8001); 

在不到 20 行代碼中(實際上,真正實現功能的代碼只有 8 行),您已經構建了一個能夠使用的聊天服務器。下面是這個簡單程序的流程:

◆ 當一個套接字進行連接時,將該套接字對象附加到一個數組。

◆ 當客戶端寫入它們的連接時,將該數據寫到所有的套接字。

現在,讓我們檢查所有代碼,并解釋這個例子如何實現聊天服務器預定功能。***行允許訪問 net 模塊的內容:

  1. net = require(‘net’); 

讓我們使用這個模塊中的 Server。

您將需要一個位置來保存所有客戶端連接,以便在寫入數據時可以寫到它們中去。下面是用于保存所有客戶端套接字連接的變量:

  1. var sockets = [];  

下一行開始一個代碼塊,規(guī)定當每個客戶端連接時要做的事情。

  1. var s = net.Server(function(socket) { 

傳遞到 Server 中的惟一參數是將針對每個客戶端連接進行調用的一個函數。在這個函數中,將客戶端連接添加到所有客戶端連接的列表中:

  1. sockets.push(socket); 

下一部分代碼建立了一個事件處理器,規(guī)定了當一個客戶端發(fā)送數據時要做的事情:

  1. socket.on(‘data’, function(d) {   
  2. for (var i=0; i < sockets.length; i++ ) {   
  3. sockets[i].write(d);   
  4. }   
  5. }); 

socket.on() 方法調用為節(jié)點注冊一個事件處理器,以便當某些事件發(fā)生時它知道如何處理。當接收到來自客戶端的數據時,Node.js 會調用這個特殊的事件處理器。其他的事件處理器包括 connect、end、timeout、drain、error 和 close。

socket.on() 方法調用的結構類似于前面提過的 Server() 調用。您傳入一個函數給這兩者,當有事發(fā)生時調用此函數。這種回調方法在異步網絡框架中很常見。這是當開始使用像 Node.js 這樣的異步框架時,擁有過程編程經驗的人會遇到的主要問題。

在這種情況下,當任意客戶端發(fā)送數據給服務器時,就會調用這個匿名函數并將數據傳入函數中。它基于您已經積累的套接字對象列表進行迭代,并給它們全部發(fā)送相同的數據。每個客戶端連接都將接收到這些數據。

這個聊天服務器十分簡單,它缺少一些非?;A的功能,比如識別是誰發(fā)送哪條消息,或者處理某個客戶端斷開的情況。(如果一個客戶端從這臺聊天服務器斷開,任何人發(fā)送消息,服務器都會崩潰。)

下面的源代碼(在下載示例文件中叫做 chat2.js )是一個經過改進的套接字服務器,其功能有所增強,能夠處理“糟糕的情況“(比如客戶端斷開)。

  1. net = require(‘net’);   
  2. var sockets = [];   
  3. var name_map = new Array();   
  4. var chuck_quotes = [   
  5. "There used to be a street named after Chuck Norris, but it was changed because   
  6. nobody crosses Chuck Norris and lives.",   
  7. "Chuck Norris died 20 years ago, Death just hasn't built up the courage to tell   
  8. him yet.",   
  9.  
  10. "Chuck Norris has already been to Mars; that's why there are no signs of life.",   
  11. "Some magicians can walk on water, Chuck Norris can swim through land.",   
  12. "Chuck Norris and Superman once fought each other on a bet. The loser had to start   
  13. wearing his underwear on the outside of his pants."   
  14. ]   
  15.  
  16.    
  17.  
  18. function get_username(socket) {   
  19. var name = socket.remoteAddress;   
  20. for (var k in name_map) {   
  21. if (name_map[k] == socket) {   
  22. name = k;   
  23. }   
  24. }   
  25. return name;   
  26. }   
  27.  
  28.    
  29.  
  30. function delete_user(socket) {   
  31. var old_name = get_username(socket);   
  32. if (old_name != null) {   
  33. delete(name_map[old_name]);   
  34. }   
  35. }   
  36.  
  37.    
  38.  
  39. function send_to_all(message, from_socket, ignore_header) {   
  40. username = get_username(from_socket);   
  41. for (var i=0; i < sockets.length; i++ ) {   
  42. if (from_socket != sockets[i]) {   
  43. if (ignore_header) {   
  44. send_to_socket(sockets[i], message);   
  45. }   
  46. else {   
  47. send_to_socket(sockets[i], username + ‘: ‘ + message);   
  48. }   
  49. }   
  50. }   
  51. }   
  52.  
  53.    
  54.  
  55. function send_to_socket(socket, message) {   
  56. socket.write(message + ‘\n’);   
  57. }   
  58. function execute_command(socket, command, args) {   
  59. if (command == ‘identify’) {   
  60. delete_user(socket);   
  61. name = args.split(‘ ‘, 1)[0];   
  62. name_map[name] = socket;   
  63. }   
  64. if (command == ‘me’) {  
  65. name = get_username(socket);   
  66. send_to_all(‘**’ + name + ‘** ‘ + args, socket, true);   
  67. }   
  68. if (command == ‘chuck’) {   
  69. var i = Math.floor(Math.random() * chuck_quotes.length);   
  70. send_to_all(chuck_quotes[i], socket, true);   
  71. }   
  72. if (command == ‘who’) {   
  73. send_to_socket(socket, ‘Identified users:’);   
  74. for (var name in name_map) {   
  75. send_to_socket(socket, ‘- ‘ + name);   
  76. }   
  77. }   
  78. }   
  79.  
  80.    
  81.  
  82. function send_private_message(socket, recipient_name, message) {   
  83. to_socket = name_map[recipient_name];   
  84. if (! to_socket) {   
  85. send_to_socket(socket, recipient_name + ‘ is not a valid user’);   
  86. return;   
  87. }   
  88. send_to_socket(to_socket, ‘[ DM ' + get_username(socket) + ' ]: ‘ + message);   
  89. }   
  90.  
  91.    
  92.  
  93. var s = net.Server(function(socket) {   
  94. sockets.push(socket);   
  95. socket.on(‘data’, function(d) {   
  96. ddata = d.toString(‘utf8′).trim();   
  97. // check if it is a command   
  98.  
  99. var cmd_re = /^\/([a-z]+)[ ]*(.*)/g;   
  100. var dm_re = /^@([a-z]+)[ ]+(.*)/g;   
  101. cmd_match = cmd_re.exec(data)   
  102. dm_match = dm_re.exec(data)   
  103. if (cmd_match) {   
  104. var command = cmd_match[1];   
  105. var args = cmd_match[2];   
  106. execute_command(socket, command, args);   
  107. }   
  108. // check if it is a direct message   
  109. else if (dm_match) {   
  110. var recipient = dm_match[1];   
  111. var message = dm_match[2];   
  112. send_private_message(socket, recipient, message);   
  113. }   
  114. // if none of the above, send to all   
  115. else {   
  116. send_to_all(data, socket);   
  117. };   
  118. });   
  119. socket.on(‘close’, function() {   
  120. sockets.splice(sockets.indexOf(socket), 1);   
  121. delete_user(socket);   
  122. });   
  123. });   
  124. s.listen(8001); 

#p#

稍微高級一點的主題:聊天服務器的負載平衡

通常,負載按比例增長也是部署到云環(huán)境的理由之一。這種部署需要實現一些負載平衡機制。

大多數輕量級 Web 服務器,比如 nginx 和 lighttpd,都能夠針對多臺 HTTP 服務器進行負載平衡,但如果您想要在非 HTTP 服務器之間實現平衡,nginx 可能無法滿足要求。而且盡管存在通用的 TCP 負載平衡器,您可能不會喜歡它們使用的負載平衡算法?;蛘咚鼈儧]有提供您想要使用的一些功能?;蛘?,您只是想享受構造自己的負載平衡器的樂趣。

下面是最簡單的負載平衡器。它沒有實現任何故障恢復,希望所有的目的地都是可用的,而且沒有進行任何錯誤處理。它十分簡約?;镜睦砟钍?,它接收一個來自客戶端的套接字連接,隨機挑選一個目標服務器進行連接,然后將來自客戶端的所有數據轉發(fā)給該服務器,并將來自該服務器的所有數據都發(fā)回到客戶端。

  1. net = require(‘net’);    
  2. var destinations = [   
  3. ['localhost', 8001],   
  4. ['localhost', 8002],   
  5. ['localhost', 8003],   
  6. ]   
  7.  
  8. var s = net.Server(function(client_socket) {   
  9. var i = Math.floor(Math.random() * destinations.length);   
  10. console.log(“connecting to ” + destinations[i].toString() + “\n”);   
  11. var dest_socket = net.Socket();   
  12. dest_socket.connect(destinations[i][1], destinations[i][0]);   
  13. dest_socket.on(‘data’, function(d) {   
  14. client_socket.write(d);   
  15. });   
  16. client_socket.on(‘data’, function(d) {   
  17. dest_socket.write(d);   
  18. });   
  19. });   
  20. s.listen(9001); 

destinations 的定義是我們要進行平衡的后端服務器的配置。這是一個簡單的多維數組,主機名是***個元素,端口號是第二個元素。

Server() 的定義類似于聊天服務器的例子。您創(chuàng)建一個套接字服務器,并讓它監(jiān)聽一個端口。這次它將監(jiān)聽 9001 端口。

針對 Server() 定義的回調首先隨機選擇一個要連接到的目的地:

  1. var i = Math.floor(Math.random() *   
  2. destinations.length);  

您可能已經使用過輪詢算法或使用“最少連接數“算法完成一些額外的工作然后離去,但我們想盡可能地保持簡單。

這個例子中有兩個指定的套接字對象: client_socket 和 dest_socket。

◆ client_socket 是負載平衡器與客戶端之間的連接。

◆ dest_socket 是負載平衡器與被平衡服務器之間的連接。

這兩個套接字分別處理一個事件:接收到的數據。當它們其中一個收到數據時,就會將數據寫到另一個套接字。

讓我們完整地了解當一個客戶端通過負載平衡器連接到通用網絡服務器上,發(fā)送數據,然后接收數據時發(fā)生的事情。

當一個客戶的連接到負載平衡器時,Node.js 在客戶端與自己本身之間創(chuàng)建一個套接字,我們稱之為 client_socket。

當連接建立之后,負載平衡器挑選一個目的地并創(chuàng)建一個指向該目的地的套接字連接,我們稱之為 dest_socket。

當客戶端發(fā)送數據時,負載平衡器將相同的數據推送到目的地服務器。

當目的地服務器做出響應并將一些數據寫到 dest_socket 時,負載平衡器通過client_socket 將這些數據推送回客戶端。

可以對這個負載平衡器進行一些改進,包括錯誤處理,在同一個進程中嵌入另一個進程以動態(tài)增加和移除目的地,增加不同的平衡算法,以及增加一些容錯處理。

超越原生解決方案:Express Web 框架

Node.js 配備有 HTTP 服務器功能,但較為低級。如果要在 Node.js 中構建一個 Web 應用程序,您可能會考慮 Express——一個為 Node.js 打造的 Web 應用程序開發(fā)框架。它彌補了 Node.js 的一些不足。

在下一個例子中,讓我們重點關注使用 Express 勝過簡單的 Node.js 的一些明顯優(yōu)勢。請求路由就是其中之一,還有一個是為 HTTP “verb” 類型注冊一個事件,比如“get”或“post”。

下面給出了一個十分簡單的 Web 應用程序,它只是演示了 Express 的一些基本功能。

  1. ar app = require(‘express’).createServer();   
  2. app.get(‘/’, function(req, res){   
  3. res.send(‘This is the root.’);   
  4. });   
  5.  
  6. app.get(‘/root/:id’, function(req, res){   
  7. res.send(‘You sent ‘ + req.params.id + ‘ as an id’);   
  8. });   
  9. app.listen(7000); 

這兩行以 app.get() 開始的代碼是事件處理器,當 GET 請求進入時就會觸發(fā)。這兩次方法調用的***個參數是一個正則表達式,用于指定用戶可能傳入的 URL。第二個參數是真正處理請求的一個函數。

正則表達式參數是路由機制。如果請求類型(GET、POST等)與資源(/, /root/123)匹配,就會調用處理器函數。在***次app.get() 調用中,/ 被簡單地指定為資源。而在第二次調用中,在指定/root 時后面還加了一個 ID。映射 regex 的 URL 中資源前面的冒號(:) 字符表明,這部分稍后可作為一個參數使用。

當請求類型與正規(guī)表達式匹配時,就會調用處理器函數。此函數帶有兩個參數,一個請求(req)和一個響應(res)。前面提到的參數被附加給請求對象。而 Web 服務器傳回給用戶的消息被傳入到響應對象。

這是一個非常簡單的例子,但已經清楚地說明“真正的應用程序“如何利用這個框架來構建更加豐富和完整的功能。如果插入一個模板系統(tǒng)和一些數據引擎(傳統(tǒng)的或 NoSQL 均可),您可以輕松構建出一組功能來滿足真正應用程序的需求。

Express 的特點之一是高性能。這與其他快速 Web 應用程序框架的常見特性一起,讓Express 在注重高性能和海量可伸縮性的云部署領域中占據了重要的位置。

應了解的知識

有兩個概念/趨勢需要了解:

◆ 鍵/值數據庫的突然流行。

◆ 其他異步的 Web 范型。

鍵/值數據庫… 為什么突然流行?

因為 JavaScript 是 Web 的通用語言,對于 JavaScript Object Notation (JSON) 的討論通常遠遠落后于 JavaScript 相關的研究。 JSON 是在 JavaScript 與一些其他語言之間交換數據的最常用途徑。JSON 本質上是一種鍵/值存儲,因此天生適用于對鍵/值數據庫感興趣的JavaScript 和 Node.js 開發(fā)人員。畢竟,如果能夠以 JSON 格式存儲數據,JavaScript 開發(fā)人員的工作就將變得輕松很多。

有一個不太相關的趨勢,在 NoSQL 數據庫環(huán)境中也會涉及鍵/值數據庫。CAP 定理(也叫做 Brewer 定理)指出,一個分布式系統(tǒng)有 3 個核心屬性:一致性、可用性和分區(qū)容忍性(formal proof of CAP)。這條定理是 NoSQL 發(fā)展背后的推動力量,它為犧牲傳統(tǒng)關系數據庫的某些特性以換取(通常是高可用性)提供了理論基礎。一些流行的鍵/值數據庫包括Riak、Cassandra、CouchDB 和 MongoDB。

異步 Web 范型

事件驅動的異步 Web 框架已經存在了相當長一段時間。其中***和***的異步 Web 框架是 Tornado,它使用 Python 語言編寫,在 Facebook 內部使用。下面這個例子說明了hello_world 在 Tornado 中(在下載示例文件中叫做 hello_tornado.py )是什么樣子。

  1. import tornado.ioloop   
  2. import tornado.web   
  3. class MainHandler(tornado.web.RequestHandler):   
  4. def get(self):   
  5. self.write(“Hello, world”)   
  6. application = tornado.web.Application([   
  7. (r"/", MainHandler),   
  8. ])   
  9.  
  10. if __name__ == “__main__”:   
  11. application.listen(8888)   
  12. tornado.ioloop.IOLoop.instance().start() 

Twisted.web 也是用 Python 語言寫的,工作方式也十分類似。

***談到真正的 Web 服務器本身,與 Apache 不同,nginx 不使用線程,而是使用一種事件驅動的(異步)架構來處理請求。異步 Web 框架使用 nginx 作為其 Web 服務器是十分常見的情況。

結束語

Node.js 在 Web 開發(fā)人員中非常引人關注。它允許開發(fā)團隊同時在客戶端和服務器端上編寫 JavaScript。它們還可以結合與 JavaScript 相關的強大技術:JQuery、V8、JSON 和事件驅動的編程。另外還有基于 Node.js 開發(fā)的生態(tài)系統(tǒng),比如 Express Web 框架。

Node.js 的優(yōu)點引人關注,它也存在一些缺點。如果是 CPU 密集型編程,就無法體現Node.js 提供的非阻塞 I/O 方面的優(yōu)點。有些架構可以解決這類問題,比如將一個池中的進程分流到每個 Node.js 實例上運行,但需要由開發(fā)人員去實現它。

原文:http://www.cssor.com/use-node-js-for-cloud-stack.html

【編輯推薦】

  1. 淘寶袁鋒:Node.js會令后端人員產生危機感
  2. 用Node.js開發(fā)memcache協(xié)議的反向代理服務器
  3. 基于Node.js、Express和Jscex開發(fā)的ToDo網站示例
  4. 如何安裝Node.js
  5. 什么是Node.js?
責任編輯:陳貽新 來源: 聽雨的博客
相關推薦

2015-03-10 10:59:18

Node.js開發(fā)指南基礎介紹

2021-01-14 10:48:34

Docker CompNode.js開發(fā)

2012-09-29 11:13:15

Node.JS前端開發(fā)Node.js打包

2013-05-17 09:41:02

Node.js云應用開發(fā)IaaS

2023-11-08 08:23:28

Node版本

2011-12-16 10:08:36

Node.js

2024-07-12 14:54:48

2018-08-30 16:08:37

Node.js腳手架工具

2018-06-11 14:39:57

前端腳手架工具node.js

2020-04-28 22:43:48

反向代理Node.js PHP

2022-08-28 16:30:34

Node.jsDocker指令

2021-07-03 17:43:03

Node.jsNode變量

2023-01-10 14:11:26

2013-11-01 09:34:56

Node.js技術

2022-01-07 08:00:00

Node.js開發(fā)Web

2011-11-10 11:08:34

Node.js

2019-05-05 11:47:09

TypeScript開發(fā)Node.js

2020-02-25 12:27:59

Node.jsWeb開發(fā)前端

2021-12-28 20:04:23

Node.js開發(fā)JavaScript

2020-05-29 15:33:28

Node.js框架JavaScript
點贊
收藏

51CTO技術棧公眾號