tcp不能通過瀏覽器訪問,因為他並不知道協議的特點,如果用windows開發,需要安裝'PuTTY,xsel',mac不需要
tcp屬於傳輸層 => 資料傳遞 ,傳輸層有很多協議類似於udp等
具體請參考七層協議我們最常用的http屬於應用層,tcp屬於傳輸層,也就是說應用層建立在傳輸層上,在node中為了專門實現某種傳輸手段,提供了一個tcp包
windows需要安裝telnet 控制皮膚=>程式 => telnet√一下 Telnet localhost 3000(不建議)
Telnet協議是TCP/IP協議族中的一員,是Internet遠端登陸服務的標準協議和主要方式。它為使用者提供了在本地計算機上完成遠端主機工作的能力。在終端使用者的電腦上使用telnet程式,用它連線到伺服器。終端使用者可以在telnet程式中輸入命令,這些命令會在伺服器上執行,就像直接在伺服器的控制檯上輸入一樣。
我們用putty (支援中文)
安裝後需要配置常用埠.
//node實現tcp協議 給我們提供了一個包 net模組
//tcp 互動也要有服務端和客戶端
//客戶端: 可以通過任意一個埠號給服務發請求
//服務端:接受並且響應
let net = require('net');
//建立服務端
//socket套接字 會話,http有請求和響應
// let server = net.createServer(function(socket){
// //請求到來的時候執行以下
// console.log('客戶端連結了服務端');
// })
//等同於
let server = net.createServer();
server.on('connection',function(socket){
//請求到來的時候執行以下
console.log('客戶端連結了服務端');
})
// (埠號,伺服器地址預設不寫,511(可以接收多少個請求))
//監聽成功會自動走回撥
let port = 3000;
server.listen(port,function(){
console.log(`server start ${port}`);
})
複製程式碼
我們在服務端建立埠,同時在cmd上執行,會報錯
這個我們最常見的埠衝突,我們想在埠衝突的時候讓埠自增1
我們加一行程式碼就可以解決
server.on('error',function(err){
if(err.code == 'EADDRINUSE'){
server.listen(++port)
}
})
//設定最大連線數
server.maxConnections = 2
複製程式碼
socket 是一個Duplex 就是雙攻流,可讀可寫 即客戶端一個,服務端一個,兩個是同一個人,
server.on('connection',function(socket){
//請求到來的時候執行以下
socket.write("歡迎光臨")
})
複製程式碼
設定當客戶端請求時候迴應如圖
socket.end();//關閉客戶端
server.close();//關閉自己 如果觸發了close事件就不會在觸發新的請求了
server.unref(); //表示關閉 沒有客戶端連結會自己關閉,不會觸發close事件
//接收訊息,可以通過流的方式接收到資料
socket.setEncoding('utf8')
socket.on('data' , function(data){
console.log(data)
});
複製程式碼
現在我們來實現一個聊天室, 每次連結服務端socket不是同一個人
- 提示當前線上人數多少,總共能容納多少人
- 提示請輸入使用者名稱
- 廣播訊息
//建立一個服務
let net = require('net');
let server = net.createServer();
//client儲存使用者資訊
let client = {};
//每次連結伺服器 socket每次都會產生新的
server.on('connection',function(socket){
//設定最大連線數,server.getConnections每次連線返回給客戶端資訊, socket.write讀流,通過流的方式接收到資料
server.maxConnections = 4;
server.getConnections(function(err,count){
socket.write(`歡迎光臨,當前人數為${count},總容納數${server.maxConnections}人\r\n`);
socket.write(`請輸入使用者名稱:\r\n`);
})
socket.setEncoding('utf8')
let nickName;//儲存使用者名稱
socket.setEncoding('utf8')
socket.on('data' , function(chunk){//監聽輸入
chunk = chunk.replace(/\r\n/,'');//chunk自帶換行回車
if(nickName){//把說的內容給別人看
Broadcast(nickName, chunk)
}else{
nickName = chunk;
client[chunk] = socket;
}
});
})
function Broadcast(nickName, chunk){
Object.keys(client).forEach(nick => {
if(nickName != nick){
client[nick].write(`${nickName}:${chunk}\r\n`)
}
});
}
//監聽伺服器關閉事件
server.on('close',function(){
console.log("伺服器關閉")
})
複製程式碼
下面是我們寫的全部內容
//node實現tcp協議 給我們提供了一個包 net模組
//tcp 互動也要有服務端和客戶端
//客戶端: 可以通過任意一個埠號給服務發請求
//服務端:接受並且響應
let net = require('net');
//建立服務端
//socket套接字 會話,http有請求和響應
// let server = net.createServer(function(socket){
// //請求到來的時候執行以下
// console.log('客戶端連結了服務端');
// })
let server = net.createServer();
let client = {};
//每次連結伺服器 socket每次都會產生新的
server.on('connection',function(socket){
//設定最大連線數
server.maxConnections = 4;
server.getConnections(function(err,count){
socket.write(`當前人數為${count},總容納數${server.maxConnections}人\r\n`);
socket.write(`請輸入使用者名稱:\r\n`);
})
//請求到來的時候執行以下 socket是一個Duplex 雙攻流,可讀可寫
socket.write("歡迎光臨");
//讀流,通過流的方式接收到資料
socket.setEncoding('utf8');
//監聽輸入
let nickName;
//儲存使用者名稱
socket.setEncoding('utf8')
socket.on('data' , function(chunk){
chunk = chunk.replace(/\r\n/,'');
if(nickName){
//把說的內容給別人看
Broadcast(nickName, chunk)
}else{
//chunk自帶換行回車
nickName = chunk;
client[chunk] = socket;
}
//server.close();//關閉自己 如果觸發了close事件就不會在接收新的請求了,
//server.unref(); //表示關閉 沒有客戶端,所有人都退出,連結會自己關閉,不會觸發close事件
});
//end 服務端把客戶端關掉了,,,
//socket.end();
})
function Broadcast(nickName, chunk){
Object.keys(client).forEach(nick => {
if(nickName != nick){
client[nick].write(`${nickName}:${chunk}\r\n`)
}
});
}
// (埠號,伺服器地址預設不寫,511(可以接收多少個請求))
//監聽成功會自動走回撥
let port = 3000;
server.listen(port,function(){
console.log(`server start ${port}`);
})
//如果埠被佔用,我們重啟一個埠號
server.on('error',function(err){
if(err.code == 'EADDRINUSE'){
server.listen(++port)
}
})
server.on('close',function(){
console.log("伺服器關閉")
})
複製程式碼
多功能聊天室
-
如果說話的時候富裕一些特殊意義,可以自己增加一些標識
-
look: 看所有的線上人數
-
say:zs: 私聊
-
rename: 重新命名
-
all: 廣播
-
我們有個物件 clinet 當前的人{127.0.0.1}
-
當然都是本地的,所以每個人都是這個,但是不可能同一個埠發出兩個socket ,假設第一個埠是{127.0.0.1:8080},另一個是8081,並且我們放歌物件,預設匿名,一級當前是哪個sokect
-
{127.0.0.1:8080:{nickname:'匿名',socket:socket}}
let net = require('net');
let client = {};
let server = net.createServer(function(socket){
server.maxConnections = 4;
server.getConnections(function(err,count){
socket.write(`當前人數為${count},總容納數${server.maxConnections}人\r\n`);
socket.write(`請輸入使用者名稱:\r\n`);
})
let key = socket.remoteAddress + socket.remotePort; // 遠端地址和遠端埠號
console.log(key);
socket.setEncoding('utf8');
client[key] = {nickName:'匿名',socket:socket}
socket.on('data' , function(chunk){
chunk = chunk.replace(/\r\n/,'');
let char = chunk.split(':')[0];
let content = chunk.split(':')[1];
switch(char){
case 'look':
showList(socket);
break;
case 'say':
private(content , chunk.split(':')[2],client[key].nickName);
break;
case 'rename':
rename(key, content);
break;
case 'all':
Broadcast(key , chunk, client[key].nickName)
break;
}
// key = socket.remoteAddress + socket.remotePort
// client[key] = {nickName:'匿名',socket:socket}
function showList(socket){
let users = [];
Object.keys(client).forEach(key => {
users.push(client[key].nickName)
});
socket.write(`當前使用者列表:\r\n${users.join('\r\n')}\r\n`)
}
function rename(key , chunk){
client[key].nickName = chunk;
}
function private(nickName, content , n){
let s;
Object.keys(client).forEach(key => {
if(client[key].nickName === nickName){
s = client[key].socket
}
});
s.write(`${n}: ${content}\r\n`)
}
function Broadcast(nick , chunk , nickName){
Object.keys(client).forEach(key => {
console.log(key,nick)
if(key != nick){
client[key].socket.write(`${nickName}:${chunk}\r\n`)
}
});
}
r.unref();
});
})
let port = 3000;
server.listen(port,function(){
console.log(`server start ${port}`);
})
複製程式碼
tcp寫服務端
let net = require('net');
let server = net.createServer(function(socket){
socket.write('hello');
socket.on('data',function(data){
console.log(data);
})
}).listen(3000)
//模擬客戶端,並不是通過伺服器
let net = require('net');
let socket = net.createConnection({port:3000},function(){
//同一次請求sockect就是同一個
socket.write('hi');
socket.on('data',function(data){
console.log(data);
})
})
複製程式碼