Node.js 爲實現tcp 提供了一個模塊->net 使用時直接require這個模塊前端
let net = require('net');
let server = net.createServer(function(socket){
server.maxConnections = 2;
server.getConnections(function(err,count){
socket.write(`當前最大容納${server.maxConnections},如今${count}人`)
});
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log(data);
socket.end();
server.close();
server.unref();
});
socket.on('end',function(){
console.log('客戶端關閉');
});
});
let port = 8080;
server.listen(port,'localhost',function(){
console.log(`server start ${port}`)
});
// close事件只有調用close方法纔會觸發
server.on('close',function(){
console.log('服務端關閉');
})
//當端口被佔用了,更改端口號
server.on('error',function(err){
//EADDRINUSE 當前端口號被調用
if(err.code === 'EADDRINUSE'){
server.listen(++port)
}
});
複製代碼
能夠經過telnet localhost 8080 (telnet會有亂碼問題,不太好用)
或用putty工具來訪問服務,個人設置以下,打開一個與服務器的鏈接後,回車即發送內容到服務node
let net = require('net');
let path = require('path');
let ws = require('fs').createWriteStream(path.join(__dirname,'./1.txt'));
// pipe (readale data不能同時使用)
let server = net.createServer(function(socket){
socket.pipe(ws,{end:false});
setTimeout(function(){
ws.end(); // 關閉可寫流
socket.unpipe(ws); // 取消管道
},5000)
});
server.listen(8080);
複製代碼
利用可讀流pipe方法,邊讀取客戶端輸入的內容,邊寫入文件,可是當多個客戶端輸入內容時,若是一個客戶端關閉,當前鏈接的socket就會關閉,同時會關閉ws可寫流,但多個socket用的一個ws,因此參數{end:false} 用於設置這個可寫流不關閉,其餘未關閉的客戶端仍然可寫緩存
let net = require('net');
let server = net.createServer(function(socket){
socket.pause();
socket.setTimeout(5000);
socket.on('data',function(chunk){
socket.pause();
console.log(chunk);
})
socket.on('timeout',function(){
//socket.resume();
socket.end();
});
});
server.listen(8080);
複製代碼
客戶端訪問服務端時,服務將一個文件發送給客戶端bash
先建立一個文件服務器
let fs = require('fs');
fs.writeFileSync(__dirname+'/1.txt',Buffer.alloc(1024*1024*10));
複製代碼
let net = require('net');
let rs = require('fs').createReadStream(__dirname+'/1.txt');
let server = net.createServer(function(socket){
rs.on('data',function(chunk){
let flag = socket.write(chunk);
console.log(flag);
console.log('緩存區的大小'+socket.bufferSize);
});
//可寫流的緩存區的數據所有寫到目標文件時觸發
socket.on('drain',function(){
console.log('清空緩存')
})
});
server.listen(8080);
複製代碼
socket.bufferSize : 緩存區的大小socket
socket.destroy();//銷燬sockettcp
let net = require('net');
let clients = {}; //保存{用戶名:socket}的映射
// 發言 將聊天內容發送給其餘幾我的
function broadcast(nickname,chunk){
Object.keys(clients).forEach(key=>{
//本身聊天的內容,不該該發送給本身
if(key!=nickname){
clients[key].write(`${nickname}:${chunk} \r\n`);
}
})
}
let server = net.createServer(function(socket){
server.maxConnections = 3; //容許同時3我的聊天
// 當客戶端鏈接服務端時,提示用戶輸入用戶名
server.getConnections((err,count)=>{
socket.write(`歡迎來到聊天室 當前用戶數${count}個,請輸入用戶名\r\n`);
});
let nickname;
socket.setEncoding('utf8');
//當一個用戶關閉了聊天,銷燬socket,並刪除用戶
socket.on('end',function(){
clients[nickname] &&clients[nickname].destroy();
delete clients[nickname]; // 刪除用戶
});
socket.on('data',function(chunk){
chunk = chunk.replace(/\r\n/,'')
//若是nickname存在,說明用戶輸入的是聊天內容
if(nickname){
// 發言,將聊天內容發送給其餘幾我的
broadcast(nickname,chunk);
}else{
//若是不存在nickname時,用戶輸入的內容就是nickname
nickname = chunk;
clients[nickname] = socket;
socket.write(`您的新用戶名是${nickname} \r\n`);
}
});
});
server.listen(8080);
複製代碼
該聊天室的功能以下:
一、默認狀況下用戶名是匿名
二、經過關鍵命令更名, r:用戶名
三、支持顯示在線的用戶列表 l
四、廣播的功能,將聊天內容發送給全部其餘在線用戶 b:xxx
五、私聊的功能,只發送內容給指定用戶 s:用戶名:聊天內容
函數
let net = require('net');
let clients = {};
// 更名 r命令
function rename(key,data,socket){
clients[key].nickname = data;
socket.write(`您當前的用戶名是${data}\r\n`);
}
// 展現用戶列表 l命令
function list(socket){
let str = `當前用戶列表是:\r\n`
let ls = Object.keys(clients).map(key=>{
return clients[key].nickname;
}).join('\r\n');
socket.write(str+ls+'\r\n');
}
// 私聊 nickname:用戶名 content:發送的內容 key
function private(nickname,content,key){
let user;
Object.keys(clients).forEach(function(key){
if(clients[key].nickname === nickname){
user = clients[key].socket;
}
});
user.write(clients[key].nickname+":"+content+'\r\n');
}
//廣播
function broadcast(nickname,content){
Object.keys(clients).forEach(item=>{
if(clients[item].nickname!= nickname){
clients[item].socket.write(content+'\r\n')
}
})
}
let server = net.createServer(function (socket) {
//用戶默認是匿名的,因此用socket.remoteAddress + socket.remotePort來標識一個用戶
let key = socket.remoteAddress + socket.remotePort; // 惟一
clients[key] = {nickname:'匿名',socket}//默認用戶名
server.getConnections((err, count) => {
socket.write(`歡迎來到聊天室 當前用戶${count}個\r\n`);
});
socket.setEncoding('utf8');
socket.on('data', function (chunk) {
chunk = chunk.replace(/\r\n/, '');
let chars = chunk.split(':');
switch (chars[0]) {
case 'r': // r:zhangsan
rename(key,chars[1],socket);
break;
case 'l':
list(socket);
break;
case 'b': // b:content
broadcast(key,chars[1]);
break;
case 's': // s:用戶名:content
private(chars[1],chars[2],key);
break;
default:
socket.write('當前命令沒法解析,從新輸入\r\n')
}
});
});
server.listen(8080, function () {
console.log(`server start 8080`);
})
複製代碼
let net = require('net');
let socket = net.createConnection({port:8080},function(){
socket.write('hello');
socket.on('data',function(data){
console.log(data);
});
});
複製代碼
服務端測試代碼工具
let net = require('net');
let server = net.createServer(function(socket){
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log(data);
});
});
server.on('connection',function(){
console.log('客戶端鏈接')
})
server.listen(8080);
複製代碼
啓動服務器,node命令執行客戶端文件便可看到效果測試
客戶端(不須要綁定端口,隨機分配)
let dgram = require('dgram');
//建立socket
let socket = dgram.createSocket('udp4');
//發送消息
socket.send('hello',8080,function(){
console.log('成功')
});
//接收消息
socket.on('message',function(data){
console.log(data.toString());
})
複製代碼
服務端
let dgram = require('dgram');
let socket = dgram.createSocket('udp4');
// 服務端監聽一個端口 數據到來時 能夠讀出信息
socket.bind(8080,'localhost',function(){
//讀取消息
socket.on('message',function(data,rinfo){
console.log(data.toString());
//發送消息
socket.send('hello',rinfo.port);
})
});
複製代碼