//創建新的tcp伺服器var net = require('net');var chatServer = net.createServer()chatServer.on('connection',function(client){ client.write('Hi\n'); client.writ ...
//創建新的tcp伺服器
var net = require('net');
var chatServer = net.createServer()
chatServer.on('connection',function(client){
client.write('Hi\n');
client.write('Bye\n');
client.end();
})
chatServer.listen(9000)
/*代碼的第一行,我們載入了net模塊。這個模塊包含了Node需要的所有TCP功能。
接著我們調用net.createServer()方法來廠車間一個新的TCP伺服器。有了這個
伺服器我們需要他做點事。這裡調用on()方法來添加一個事件監聽器每當有新的客戶端
通過網路連接接入伺服器,就會觸發connection事件,事件監聽器就會調用我們指定的函數。
鏈接事件在調用回調函數是,會傳給我們新的客戶端對應的TCP scoket對象的引用。我們把
他引用命名為client。調用client.write(),就能發送信息給該客戶端,然後調用client.end()
方法關閉連接。
*/
//監聽所有的鏈接請求
var net = require('net');
var chatServer = net.createServer()
chatServer.on('connection',function(client){
client.write('Hi\n');
client.on('data',function(data){
console.log(data)
})
})
chatServer.listen(9000)
/*這裡添加了另外一個事件監聽器,調用的是client.on()。註意我們是在connection回調函數作用域
中添加事件監聽器,這樣就能訪問到鏈接事件所對應的client對象。新監視器關註的是data事件,每當
client發送數據給伺服器時,這一事件都會觸發*/
//客戶端之間的通信
var net = require('net')
var chatServer = net.createServer(),
clientList = []
chatServer.on('connection',function(client){
client.write('Hi!\n');
clientList.push(client)
client.on('data',function(data){
for (var i = 0; i < clientList.length; i+=1) {
//把數據發送給客戶端
clientList[i].write(data)
}
})
})
chatServer.listen(9000)
/*伺服器沒有接收記錄他收到的任何消息,而且把列表中的每個客戶端都輪詢一遍,
並把消息轉發出去,發送消息的時候,沒有檢查發送者是誰,只是簡單的把消息轉發
給所有的客戶端*/
//改進消息發送
var net = require('net')
var chatServer =net.createServer(),
clientList = []
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){
broadcase(data,client)
})
})
function broadcase(message,client){
for(var i = 0;i < clientList.length;i += 1){
if(client !== clientList[i]){
clientList[i].write(client.name + "says: " + message + '\n')
}
}
}
chatServer.listen(9000)
/*在connection事件監聽器上為每個client對象上增加name屬性
為什麼我們能為client對象添加屬性
因為閉包綁定了每個client對象和相應的請求。於是,在閉包內疚可以利用
client.remoteAddress和client.remotePort來創建client和name屬性
client.remoteAddress是客戶端所在的IP地址
client,remotePort是客戶端接收從伺服器返回數據的TCP埠
當不同的客戶端從一個IP發起連接時,他們各自會有唯一的remotePort。
以後再向client發送消息時,我們就能唯一標識來找到他
我們還把處理data的事件監聽器放到了broadcast函數中,這樣,通過
調用broadcast函數就可以把消息發送到所有客戶端。這一次,把發起消息
data的client對象傳遞進去,以便把他從接收消息的客戶端列表中排除掉。
我們還把client.name加到要發送的消息上,好讓其他客戶端清楚消息來源*/
/*此種通信弊端:建立3個tcp通信,當斷掉其中一個,在向其發送消息,即
調用broadcast()的時候,伺服器會往一個斷開的客戶端寫入數據,因為他所對應
的socket已經無法寫入和讀取了,而對socket進行write()操作時,Node程式會拋出
異常,這將導致其他伺服器掉線
這個問題應該從兩個方面來解決,首先保證在一個客戶端斷開的時候,要把他從客戶端
列表中移除,防止他在調用write方法。V8引擎也會把相應的scoket對象作為垃圾回收
並釋放記憶體。其次,更保險的方式不調用write方法*/
//把聊天伺服器改造的更加健壯
var net = require('net')
var chatServer =net.createServer(),
clientList = []
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){
broadcase(data,client)
})
client.on('end',function(){
clientList.splice(clientList.indexOf(client),1)
})
})
function broadcase(message,client){
for(var i = 0;i < clientList.length;i += 1){
if(client !== clientList[i]){
clientList[i].write(client.name + "says: " + message + '\n')
}
}
}
chatServer.listen(9000)
/*先處理斷開的客戶端。當一個客戶端斷開時,要把它從客戶端列表移除。這時
可以用end事件來完成。一個socket斷開連接會觸發end事件,表示他要關閉。
此時,調用Array.splice()將客戶端從cliectList列表移除。Array.indexOf()
方法用於找到客戶端在列表的位置,然後splice()把他從列表移除。之後,
下一個客戶端調用broadcast方法時,已經斷開的客戶端將不出現在列表中*/
//檢查socke的可寫狀態
var net = require('net')
var chatServer =net.createServer(),
clientList = []
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){
broadcase(data,client)
})
})
function broadcase(message,client){
var cleanup = []
for(var i = 0;i < clientList.length;i += 1){
if(client !== clientList[i]){
if(clientList[i].writable){
clientList[i].write(client.name + "says: " + message + '\n')
} else{
cleanup.push(clientList[i])
clientList[i].destroy()
}
}
}
//在寫如入迴圈中刪除死節點,消除垃圾索引
for(i = 0;i < cleanup.length;i += 1){
clientList.splice(clientList.indexOf(cleanup[i]),1)
}
}
chatServer.listen(9000)
/*調用broadcast函數的時候,檢查一下socket是否可寫,以確保不會因為任何一個不可寫
的socket導致異常。不僅如此,發現任何不可寫的socket後,還要通過Socket.destroy()
方法將其關閉並從clientList中移除。註意,遍歷clientList的過程沒有移除socket,*/