阅读 102

node之tcp篇入门理解

在Node.js中,net模块实现了基于TCP的数据通信

// node实现tcp协议 给我们提供了一个包 net模块
let net = require('net');
// socket套接字 会话,http的请求和响应就是基于socket拆分出来的
let server = net.createServer();
// 当客户端请求时,会触发 connection
server.on('connection',function (socket) {
 console.log('客户端请求到来了')
});
let port = 3000;
server.listen(port,function () {
  console.log(`server start ${port}`);
});
复制代码

服务器监听3000端口事件,开启服务,此时命令行输入 telnet localhost 3000,触发'connection'事件,打印出'客户端请求到来了'

socket是一个Duplex 双工流,服务器既可以可以给客户端写东西,也可以收到客户端的东西;同样客户端既可以收到服务端发的东西,也可以给服务器发东西。 如下:

server.on('connection',function (socket) {
     console.log('客户端请求到来了')
    //socket是一个Duplex双工流, 可读可写
      socket.write('欢迎光临');//服务器给客户端写了‘欢迎光临’
      //socket.end(); // 服务器关掉客户端
      socket.setEncoding('utf8');// 设置编码格式
      // 可以通过流的方式接收到客户端发来的消息
      socket.on('data',function (data) {
         console.log(data);
      });
  });
复制代码

socket.end()是服务器关掉客户端,那么服务器可以不可以关闭自己呢?答案是可以的。有两种方式: server.close() vs server.unref() server.close():如果触发close事件就不会再接收新的请求了。当处理完手头里的请求后,会触发close事件并把自己关闭。 server.unref(): 如果触发unref事件依然会接收新请求,当处理所有请求后,会把自己关闭,不会触发close事件。

// 写一个聊天室 
server.on('connection',function (socket) {
  //socket是一个Duplex 可读可写
  socket.write('欢迎光临');
  //socket.end(); // 相当于关掉客户端
  socket.setEncoding('utf8');
  // 可以通过流的方式接收到数据
  socket.on('data',function (data) {
     console.log(data);
     server.close(); // 如果触发close事件就不会再接收新的请求了
     //server.unref(); // 也表示关闭 ,没有客户端连接会自己关闭(不会触发close事件)
     // unref可以接收新的请求,close不能接收新的请求了
  });
});
server.on('close',function () {
  console.log('服务器关闭');
});

复制代码

另外我们可以设置最大客户端连接数目:

//设置最大链接数以及监听客户端的链接数量
server.getConnections((err,count)=>{
    console.log('已经链接'+count+'个用户')
});
server.maxConnections = 2; // 设置最大连接数,超过数量不能连接
复制代码

接下来我们基于tcp写一个简单的聊天室吧 自定义下规则: // l 表示看所有的在线人数 // s:zs:哈哈 表示:私信给zs,内容是哈哈 // r:zs 将自己重命名为zs // b 表示广播和所有人说话

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`);
  });
  let key = socket.remoteAddress + socket.remotePort;//每个用户的唯一标示
  socket.setEncoding('utf8');
  client[key] = { nickName: '匿名', socket };
  socket.on('data', function (chunk) {
    chunk = chunk.replace(/\r\n/g, '');
    let char = chunk.split(':')[0];
    let content = chunk.split(':')[1];
    switch (char) {
      case 'l':
        showList(socket); // 显示用户列表
        break;
      case 's': // s:zs:内容
        private(chunk.split(':')[1], chunk.split(':')[2], client[key].nickName);
        break;
      case 'r':
        rename(key, content); // r:xxx
        break;
      case 'b':
        broadcast(chunk.split(':')[1], client[key].nickName);
      default:
        break;
    }
  })
});
复制代码

显示列表:

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;
}
复制代码

私信:

/**
nickName:被私信的人
content:私信的内容
n:主动私信的人
**/
function private(nickName, content, n) {
  // {key:{nickName,socket}}
  let s;
  Object.keys(client).forEach(key => {
    if (client[key].nickName === nickName) {
      s = client[key].socket
    }
  });
  s.write(`${n}:${content}\r\n`);
}
复制代码

广播:

/**
chunk:内容
nickName:广播人的名字
**/
function broadcast(chunk, nickName) {
  Object.keys(client).forEach((nick) => {
    if (client[nick].nickName !== nickName) {
      client[nick].socket.write(`${nickName}:${chunk}\r\n`);
    }
  });
}
复制代码

tcp不仅可以创建服务端还可以创建客户端

let net = require('net');
// 创建tcp客户端
let socket = net.createConnection({port:3000},function () {
  socket.write('hello');
  socket.on('data',function (data) {
    console.log(data);
  })
});
复制代码
文章分类
前端