成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用Node.js作為完整的云環境開發堆棧

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

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

51CTO推薦專題:Node.js專區

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

Node.js 云計算平臺

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

圖 1. PaaS 與 IaaS 結構

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

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

使用 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. > 

在這個例子中,創建了對象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’ 

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

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

用 Node.js 構建聊天服務器

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

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

  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 = [];  

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

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

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

  1. sockets.push(socket); 

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

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

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

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

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

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

下面的源代碼(在下載示例文件中叫做 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#

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

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

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

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

  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() 的定義類似于聊天服務器的例子。您創建一個套接字服務器,并讓它監聽一個端口。這次它將監聽 9001 端口。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

在下一個例子中,讓我們重點關注使用 Express 勝過簡單的 Node.js 的一些明顯優勢。請求路由就是其中之一,還有一個是為 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 請求進入時就會觸發。這兩次方法調用的***個參數是一個正則表達式,用于指定用戶可能傳入的 URL。第二個參數是真正處理請求的一個函數。

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

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

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

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

應了解的知識

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

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

◆ 其他異步的 Web 范型。

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

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

有一個不太相關的趨勢,在 NoSQL 數據庫環境中也會涉及鍵/值數據庫。CAP 定理(也叫做 Brewer 定理)指出,一個分布式系統有 3 個核心屬性:一致性、可用性和分區容忍性(formal proof of CAP)。這條定理是 NoSQL 發展背后的推動力量,它為犧牲傳統關系數據庫的某些特性以換取(通常是高可用性)提供了理論基礎。一些流行的鍵/值數據庫包括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 開發人員中非常引人關注。它允許開發團隊同時在客戶端和服務器端上編寫 JavaScript。它們還可以結合與 JavaScript 相關的強大技術:JQuery、V8、JSON 和事件驅動的編程。另外還有基于 Node.js 開發的生態系統,比如 Express Web 框架。

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

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

【編輯推薦】

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

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2021-01-14 10:48:34

Docker CompNode.js開發

2012-09-29 11:13:15

Node.JS前端開發Node.js打包

2013-05-17 09:41:02

Node.js云應用開發IaaS

2023-11-08 08:23:28

Node版本

2018-06-11 14:39:57

前端腳手架工具node.js

2018-08-30 16:08:37

Node.js腳手架工具

2011-12-16 10:08:36

Node.js

2020-04-28 22:43:48

反向代理Node.js PHP

2024-07-12 14:54:48

2022-08-28 16:30:34

Node.jsDocker指令

2013-11-01 09:34:56

Node.js技術

2023-01-10 14:11:26

2021-07-03 17:43:03

Node.jsNode變量

2011-11-10 11:08:34

Node.js

2022-01-07 08:00:00

Node.js開發Web

2019-05-05 11:47:09

TypeScript開發Node.js

2021-12-28 20:04:23

Node.js開發JavaScript

2020-02-25 12:27:59

Node.jsWeb開發前端

2021-12-25 22:29:57

Node.js 微任務處理事件循環
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久久国产精品 | 欧美黑人又粗大 | 色婷婷一区二区三区四区 | 中文在线www | 国产黄色麻豆视频 | 给我免费的视频在线观看 | 国产欧美精品一区二区 | 久久国产高清 | 成人av在线播放 | 91综合网| 国产精品一区久久久久 | 奇米超碰 | 91欧美精品成人综合在线观看 | 色综合色综合网色综合 | 亚洲精品视频一区 | 亚洲高清视频一区 | 国产精品一区二区在线播放 | 亚洲日产精品 | 精品国产1区2区3区 在线国产视频 | 男人av网| 伊人网91 | www操操| av免费网站在线观看 | 日韩有码一区 | 玖玖视频免费 | 天天综合网永久 | 精品国产乱码久久久久久闺蜜 | 免费a v网站 | 毛片链接 | 欧美一区二区三区在线视频 | 日韩一区二区三区四区五区 | 国产精品久久久精品 | 91xxx在线观看| 亚洲国产成人av | 国产精品久久久久久婷婷天堂 | 视频1区| 成人视屏在线观看 | 超碰在线人人 | 美女视频一区二区三区 | 成人av在线播放 | 欧美中文字幕 |