欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

學(xué)習(xí) NodeJS 第八天:Socket 通訊實(shí)例

 更新時(shí)間:2016年12月21日 14:55:12   作者:zhangxin09  
本篇文章主要介紹了學(xué)習(xí) NodeJS 第八天:Socket 通訊實(shí)例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。

前言

一般來(lái)講,HTTP 是基于文本的“單向”通訊機(jī)制。這里所謂的“單向”,乃相對(duì)于“雙向”而言,因?yàn)?HTTP 服務(wù)器只需根據(jù)請(qǐng)求返還恰當(dāng)?shù)?HTML 給客戶端即可,不涉及客戶端向服務(wù)端的通訊。這種單向的機(jī)制比較簡(jiǎn)單,對(duì)網(wǎng)絡(luò)質(zhì)量要求也不高。而更多的場(chǎng)景則是需要可靠、穩(wěn)定的端到端連接。一般這種服務(wù)是實(shí)時(shí)的、有態(tài)的而且是長(zhǎng)連接,長(zhǎng)連接則暗示兩段須達(dá)致相向通訊的能力,也就說(shuō)是服務(wù)端客戶端兩者間能夠?qū)崟r(shí)地相互間通信。毫無(wú)疑問(wèn),能夠?qū)崟r(shí)通信的服務(wù)器正是我們對(duì)服務(wù)器基本要求之一。區(qū)別于 HTTP 服務(wù)器以 HTTP 為通訊協(xié)議, 實(shí)時(shí)服務(wù)器一般采用較為底層的 TCP/IP 為協(xié)議通訊,實(shí)現(xiàn)了“套字節(jié) Socket”的雙向機(jī)制。

Socket 是根據(jù)博克萊 (U.C.Berkley) 大學(xué)早期發(fā)展的 Socket 概念寫成的,其設(shè)計(jì)理念是是將網(wǎng)絡(luò)傳輸類比成文件的讀取與寫入 (傳送的動(dòng)作被視為是寫入/接收的動(dòng)作被視為是讀取),如此、傳送與接收就簡(jiǎn)化為編程人員比較容易懂的 讀取與寫入,降低了網(wǎng)絡(luò)編程的學(xué)習(xí)困難度。

聊天室服務(wù)器

聊天室的實(shí)時(shí)連接基于底層的 TCP 直接連接,為此我們須調(diào)用 Node 的 TCP 模塊。如果不太熟悉所謂 TCP 網(wǎng)絡(luò)編程?太底層了是不是?沒(méi)關(guān)系,我也不熟悉,邊學(xué)邊做嘛,只不過(guò)千萬(wàn)不必因?yàn)橛龅侥吧脑~匯而害怕,其實(shí)這樣原理并不深?yuàn)W,而且下面的例子也十分的簡(jiǎn)單易懂!咱們就從最簡(jiǎn)單的開始吧,下面代碼僅僅十行,它的作用是服務(wù)器向客戶端輸出一段文本,完成 Sever --> Client 的單向通訊。

// Sever --> Client 的單向通訊 
var net = require('net'); 
 
var chatServer = net.createServer(); 
 
chatServer.on('connection', function(client) { 
 client.write('Hi!\n'); // 服務(wù)端向客戶端輸出信息,使用 write() 方法 
 client.write('Bye!\n'); 
 
 client.end(); // 服務(wù)端結(jié)束該次會(huì)話 
}); 
 
chatServer.listen(9000); 

客戶端可以是系統(tǒng)自帶的 Telnet:

telnet 127.0.0.1 9000 

執(zhí)行 telnet 后,與服務(wù)點(diǎn)連接,反饋 Hi! Bye! 的字符,并立刻結(jié)束服務(wù)端程序終止連接。如果我們要服務(wù)端接到到客戶端的信息?可以監(jiān)聽 server.data 事件并且不要中止連接(否則會(huì)立刻結(jié)束無(wú)法接受來(lái)自客戶端的消息):

// 在前者的基礎(chǔ)上,實(shí)現(xiàn) Client --> Sever 的通訊,如此一來(lái)便是雙向通訊 
var net = require('net'); 
var chatServer = net.createServer(),  
 clientList = []; 
  
chatServer.on('connection', function(client) { 
 // JS 可以為對(duì)象自由添加屬性。這里我們添加一個(gè) name 的自定義屬性,用于表示哪個(gè)客戶端(客戶端的地址+端口為依據(jù)) 
 client.name = client.remoteAddress + ':' + client.remotePort; 
 client.write('Hi ' + client.name + '!\n'); 
 clientList.push(client); 
 client.on('data', function(data) {  
  broadcast(data, client);// 接受來(lái)自客戶端的信息 
 }); 
}); 
function broadcast(message, client) { 
 for(var i=0;i<clientList.length;i+=1) {  
  if(client !== clientList[i]) {  
  clientList[i].write(client.name + " says " + message);  
  } 
 } 
} 
chatServer.listen(9000); 

這里要說(shuō)明一下的是,不不同操作系統(tǒng)對(duì)端口范圍的限制不一樣,有可能是隨機(jī)的。

那么上面是不是一個(gè)完整功能的代碼呢?我們說(shuō)還有一個(gè)問(wèn)題沒(méi)有考慮進(jìn)去:那就是一旦某個(gè)客戶端退出,卻仍保留在 clientList 里面,這明顯是一個(gè)空指針(NullPoint)。如果是在這樣的話我們寫程序太脆弱了,能不能更健壯一些?——請(qǐng)接著看。

首先我們簡(jiǎn)單地把 client 從數(shù)組 clientList 中移除掉。完成這工作一點(diǎn)都不困難。Node TCP API 已經(jīng)為我們提供了 end 事件,即客戶端中止與服務(wù)端連接的時(shí)候發(fā)生。移除 client 對(duì)象的代碼如下:

chatServer.on('connection', function(client) { 
 client.name = client.remoteAddress + ':' + client.remotePort 
 client.write('Hi ' + client.name + '!\n'); 
 
 clientList.push(client) 
 
 client.on('data', function(data) { 
 broadcast(data, client) 
 }) 
 
 client.on('end', function() { 
 clientList.splice(clientList.indexOf(client), 1); // 刪除數(shù)組中的制定元素。這是 JS 基本功哦~ 
 }) 
}) 

但是我們還不敢說(shuō)上述代碼很健壯,因?yàn)橐坏?end 沒(méi)有被觸發(fā),異常仍然存在著。下面我們看看解決之道:重寫 broadcast():

function broadcast(message, client) { 
 var cleanup = [] 
 for(var i=0;i<clientList.length;i+=1) { 
 if(client !== clientList[i]) { 
 
  if(clientList[i].writable) { // 先檢查 sockets 是否可寫 
  clientList[i].write(client.name + " says " + message) 
  } else { 
  cleanup.push(clientList[i]) // 如果不可寫,收集起來(lái)銷毀。銷毀之前要 Socket.destroy() 用 API 的方法銷毀。 
  clientList[i].destroy() 
  } 
 
 } 
 } //Remove dead Nodes out of write loop to avoid trashing loop index 
 for(i=0;i<cleanup.length;i+=1) { 
 clientList.splice(clientList.indexOf(cleanup[i]), 1) 
 } 
} 

TCP API 中還提供一個(gè) error 事件,用于捕捉客戶端的異常:

client.on('error', function(e) { 
 console.log(e); 
}); 

Node 網(wǎng)絡(luò)編程的 API 還豐富,此次僅僅是個(gè)入門,更多的內(nèi)容請(qǐng)接著看,關(guān)于瀏覽器 Socket 應(yīng)用。

Socket.IO

前面說(shuō)到,瀏覽器雖然也屬于客戶端的一種,但僅支持“單工”的 HTTP 通訊。有見及此,HTML5 新規(guī)范中推出了基于瀏覽器的 WebSocket,開發(fā)了底層的接口,允許我們能進(jìn)行 更強(qiáng)大的操作,超越以往的 XHR。

如第一個(gè)例子那般,我們無(wú)須第三方框架就可以直接與 Node TCP 服務(wù)器 進(jìn)行 Socket  通訊。

但我們又要認(rèn)清一個(gè)事實(shí),不是每個(gè)瀏覽器都可以順利支持 WebSocket 的。于是 Socket.IO (http://socket.io)出現(xiàn)了,它提供了不支持 WebSocket 時(shí)候的降級(jí)支持,同時(shí)使得一些舊版本的瀏覽器也可以“全雙工”地工作。優(yōu)先使用的順序如下:

  • WebSocket
  • Socket over Flash API
  • XHR Polling 長(zhǎng)連接
  • XHR Multipart Streaming
  • Forever Iframe
  • JSONP Polling

經(jīng)過(guò)封裝,我們可以不探究客戶端使用上述哪一種技術(shù)達(dá)致“全雙工”;而我們編寫代碼時(shí),亦無(wú)論考慮哪種放法,因?yàn)?Socket.IO 給我們的 API 只有一套。了解 Socket.IO 其用法就可以了。

先在瀏覽器部署 Socket.IO 的前端代碼:

<!DOCTYPE html> 
<html> 
 <body> 
 <script src="/socket.io/socket.io.js"></script> 
 <script> 
  var socket = io.connect('http://localhost:8080'); 
  // 當(dāng)服務(wù)端發(fā)送一條消息到客戶端,message 事件即被觸發(fā)。我們把消息在控制臺(tái)打印出來(lái) 
  socket.on('message', function(data){ console.log(data) }) 
 </script> 
 </body> 
</html> 

服務(wù)端 Node 代碼:

var http = require('http'), 
io = require('socket.io'), 
fs = require('fs'); 
 
// 雖然我們這里使用了同步的方法,那會(huì)阻塞 Node 的事件循環(huán),但是這是合理的,因?yàn)?readFileSync() 在程序周期中只執(zhí)行一次,而且更重要的是,同步方法能夠避免異步方法所帶來(lái)的“與 SocketIO 之間額外同步的問(wèn)題”。當(dāng) HTML 文件讀取完畢,而且服務(wù)器準(zhǔn)備好之后,如此按照順序去執(zhí)行就能讓客戶端馬上得到 HTML 內(nèi)容。 
var sockFile = fs.readFileSync('socket.html'); 
 
// Socket 服務(wù)器還是構(gòu)建于 HTTP 服務(wù)器之上,因此先調(diào)用 http.createServer() 
server = http.createServer(); 
server.on('request', function(req, res){ 
 // 一般 HTTP 輸出的格式 
 res.writeHead(200, {'content-type': 'text/html'}); 
 res.end(sockFile); 
}); 
 
server.listen(8080); 
 
var socket = io.listen(server); // 交由 Socket.io 接管 
 
// Socket.io 真正的連接事件 
socket.on('connection', function(client){ 
 console.log('Client connected'); 
 client.send('Welcome client ' + client.sessionId); // 向客戶端發(fā)送文本 
}); 

當(dāng)客戶端連接時(shí),服務(wù)端會(huì)同時(shí)出發(fā)兩個(gè)事件:server.onRequest 和 Socket.onConnection。它們之間有什么區(qū)別呢?區(qū)別在于 Socket 的是持久性的。

多個(gè) Socket 連接,先是客戶端代碼:

<!DOCTYPE html> 
<html> 
 <body> 
 <script src="/socket.io/socket.io.js"></script> 
 <script> 
  var upandrunning = io.connect('http://localhost:8080/upandrunning'); 
  var weather = io.connect('http://localhost:8080/weather'); 
  upandrunning.on('message', function(data){ 
  document.write('<br /><br />Node: Up and Running Update<br />'); 
  document.write(data); 
  }); 
  weather.on('message', function(data){ 
  document.write('<br /><br />Weather Update<br />'); 
  document.write(data); 
  }); 
 </script> 
 </body> 
</html> 

服務(wù)端代碼:

var sockFile = fs.readFileSync('socket.html'); 
 
server = http.createServer(); 
server.on('request', function(req, res){ 
 res.writeHead(200, {'content-type': 'text/html'}); 
 res.end(sockFile); 
}); 
 
server.listen(8080); 
 
var socket = io.listen(server); 
 
socket.of('/upandrunning') 
 .on('connection', function(client){ 
 console.log('Client connected to Up and Running namespace.'); 
 client.send("Welcome to 'Up and Running'"); 
}); 
 
socket.of('/weather') 
 .on('connection', function(client){ 
 console.log('Client connected to Weather namespace.'); 
 client.send("Welcome to 'Weather Updates'"); 
}); 

 如上代碼,我們可以劃分多個(gè)命名空間,分別是 upandrunning 和 weather。

關(guān)于 Express 中使用 Soclet.io,可以參考《Node:Up and Ruuning》一書的 7.2.2 小節(jié)。

今晚時(shí)間的關(guān)系,涉及 Socket.io 許多方面還沒(méi)有談,容小弟我日后再了解。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Node.js中創(chuàng)建和管理外部進(jìn)程詳解

    Node.js中創(chuàng)建和管理外部進(jìn)程詳解

    這篇文章主要介紹了Node.js中創(chuàng)建和管理外部進(jìn)程詳解,本文講解了執(zhí)行外部命令的方法、子進(jìn)程相關(guān)內(nèi)容等,需要的朋友可以參考下
    2014-08-08
  • node.js中的fs.symlink方法使用說(shuō)明

    node.js中的fs.symlink方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.symlink方法使用說(shuō)明,本文介紹了fs.symlink的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • jwt在node中的應(yīng)用實(shí)踐(安裝配置封裝)

    jwt在node中的應(yīng)用實(shí)踐(安裝配置封裝)

    這篇文章主要為大家介紹了jwt在node中的應(yīng)用實(shí)踐包括安裝配置封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Node.js?實(shí)現(xiàn)簡(jiǎn)單爬蟲的示例代碼

    Node.js?實(shí)現(xiàn)簡(jiǎn)單爬蟲的示例代碼

    本文主要介紹了Node.js?實(shí)現(xiàn)簡(jiǎn)單爬蟲,爬取美食網(wǎng)站的菜品標(biāo)題和圖片鏈接,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • node文件資源管理器的圖片預(yù)覽從零實(shí)現(xiàn)

    node文件資源管理器的圖片預(yù)覽從零實(shí)現(xiàn)

    這篇文章主要為大家介紹了node文件資源管理器的圖片預(yù)覽從零實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 搭建一個(gè)Koa后端項(xiàng)目腳手架的方法步驟

    搭建一個(gè)Koa后端項(xiàng)目腳手架的方法步驟

    這篇文章主要介紹了搭建一個(gè)Koa后端項(xiàng)目腳手架的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 輕松創(chuàng)建nodejs服務(wù)器(7):阻塞操作的實(shí)現(xiàn)

    輕松創(chuàng)建nodejs服務(wù)器(7):阻塞操作的實(shí)現(xiàn)

    這篇文章主要介紹了輕松創(chuàng)建nodejs服務(wù)器(7):阻塞操作的實(shí)現(xiàn),本文先是組出了代碼,然后對(duì)代碼一一分析,需要的朋友可以參考下
    2014-12-12
  • 把Node.js程序加入服務(wù)實(shí)現(xiàn)隨機(jī)啟動(dòng)

    把Node.js程序加入服務(wù)實(shí)現(xiàn)隨機(jī)啟動(dòng)

    這篇文章主要介紹了把Node.js程序加入服務(wù)實(shí)現(xiàn)隨機(jī)啟動(dòng),本文使用qckwinsvc實(shí)現(xiàn)這個(gè)需求,講解了qckwinsvc的安裝和使用,需要的朋友可以參考下
    2015-06-06
  • Nodejs多站點(diǎn)切換Htpps協(xié)議詳解及簡(jiǎn)單實(shí)例

    Nodejs多站點(diǎn)切換Htpps協(xié)議詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了Nodejs多站點(diǎn)切換Htpps協(xié)議詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 在Node.js中判斷路徑是否絕對(duì)的解決方法

    在Node.js中判斷路徑是否絕對(duì)的解決方法

    在不同的操作系統(tǒng)中,路徑的表示方式有很大的差異,當(dāng)編寫跨平臺(tái)的 Node.js 應(yīng)用時(shí),正確判斷路徑的絕對(duì)性變得至關(guān)重要,本文提供了path-is-absolute模塊的詳細(xì)使用指南,它是一個(gè)兼容 Node.js 早期版本且適用于所有操作系統(tǒng)的解決方案,需要的朋友可以參考下
    2024-04-04

最新評(píng)論