tcp不能經過瀏覽器訪問,由於他並不知道協議的特色,若是用windows開發,須要安裝'PuTTY,xsel',mac不須要javascript
tcp屬於傳輸層 => 數據傳遞 ,傳輸層有不少協議相似於udp等java
咱們最經常使用的http屬於應用層,tcp屬於傳輸層,也就是說應用層創建在傳輸層上,在node中爲了專門實現某種傳輸手段,提供了一個tcp包node
windows須要安裝telnet 控制面板=>程序 => telnet√一下 Telnet localhost 3000(不建議)windows
咱們用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上運行,會報錯socket
這個咱們最多見的端口衝突,咱們想在端口衝突的時候讓端口自增1tcp
咱們加一行代碼就能夠解決ui
server.on('error',function(err){
if(err.code == 'EADDRINUSE'){
server.listen(++port)
}
})
//設置最大鏈接數
server.maxConnections = 2
複製代碼
socket 是一個Duplex 就是雙攻流,可讀可寫 即客戶端一個,服務端一個,兩個是同一我的,spa
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}`);
})
複製代碼
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);
})
})
複製代碼