node.js学习(简单聊天室)

news2024/11/16 11:40:21

在掘金查看该文章

1. TCP服务搭建

1.1 socket

先来粗略了解下socket

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。 (摘自百度百科)

socket用于在两个基于TCP/IP协议的应用程序之间相互通信.最早出现在UNIX系统中,是UNIX系统主要的信息传递方式.在windows系统中,socket称为winsock.

两种形式的socket:流式套接字,对应与TCP协议.
数据报套接字,对应与UDP协议.

2.创建TCP服务端

server.js(服务端)

const net = require("net");
const sever = net.createServer();
// const clients = [];
const users = [];
const types = require("./types");
sever.on("connection", clientSocket => {
  console.log("有连接进来,请注意```");
  // clients.push(clientSocket)
  clientSocket.on("data", data => {
    console.log("监听data事件,有人说:", data.toString());
    data = JSON.parse(data.toString().trim());
    switch (data.type) {
      case types.login:
        if (users.find(item => item.nickName === data.nickName)) {
          return clientSocket.write(
            JSON.stringify({
              type: types.login,
              success: false,
              message: "昵称已存在"
            })
          );
        }
        clientSocket.nickName = data.nickName;
        users.push(clientSocket);
        clientSocket.write(
          JSON.stringify({
            type: types.login,
            success: true,
            message: "登录成功",
            nickName:data.nickName,
            sumUsers: users.length
          })
        );
        users.forEach(user=>{
          if(user!==clientSocket){
            user.write(JSON.stringify({
              type:types.log,
              message:`${data,nickName} 进入聊天室,当前在线用户数${user.length}`
            }))
          }
        })


        break;
      // 群聊天
      case types.broadcast:
         users.forEach(item => {
          item.write(JSON.stringify({
            type:types.broadcast,
            message:data.message,
            nickName:clientSocket.nickName
          }))
        })
        break;
      // 点对点
      case types.p2p:
        const user = users.find(item => item.nickName === data.nickName)
        if(!user){
          return clientSocket.write(JSON.stringify({
            type:types.p2p,
            success:false,
            message:"该用户不存在"
          }))
        }
        console.log('clientSocket.nickName',clientSocket.nickName)
        user.write(JSON.stringify({
          type:types.p2p,
          message:data.message,
          nickName:clientSocket.nickName,
          success:true
        }))

        break;
      default:
        break;
    }
  });
  
  // 离线
  clientSocket.on("end",()=>{
    console.log("有用户离线了~~~")
    const index =users.findIndex(user => user.nickName === clientSocket.nickName)
    if(index !== -1){
      const offlineUser = users[inde]
      users.splice(index,1)
      users.forEach(user=>{
        if(user!==clientSocket){
          user.write(JSON.stringify({
            type:types.log,
            message:`${offlineUser,nickName} 离开了聊天室,当前在线用户数${user.length}`
          }))
        }
      })
    }
  })
  // clientSocket.write('hello,返回的是buffer,用tostring转一下哦')
});

sever.listen(2000, () => {
  console.log("server running  127.0.0.1 2000");
});

3.创建客户端

client.js(客户端)

const net = require("net");
const types = require("./types");
let nickName = null;
const client = net.createConnection({
  host: "127.0.0.1",
  port: 2000
});

client.on("connect", () => {
  console.log("连接成功了~~~");
  process.stdout.write("请输入昵称:");

  // 连接完毕后,可以监听终端的信息,发给服务端
  process.stdin.on("data", data => {
    data = data.toString().trim();
    console.log("nickName", nickName);
    if (!nickName) {
      client.write(
        JSON.stringify({
          type: types.login,
          nickName: data
        })
      );
    }
    const matches = /^@(\w+)\s(.+)$/.exec(data);
    if (matches) {
      //符合 @xxx xxx  格式
      return client.write(
        JSON.stringify({
          type: types.p2p,
          nickName: matches[1],
          message: matches[2]
        })
      );
    }
    //群聊天
    client.write(
      JSON.stringify({
        type: types.broadcast,
        message: data
      })
    );
  });
});

client.on("data", data => {
  // console.log("服务端发来的data:::", data.toString());
  data = JSON.parse(data.toString().trim());
  switch (data.type) {
    case types.login:
      if (!data.success) {
        console.log("登录失败", `${data.message}`);
        process.stdout.write("请输入昵称");
      } else {
        process.stdout.write("登录成功,当前在线人数:", data.sumUsers);
        nickName = data.nickName;
      }
      break;
    case types.broadcast:
      console.log(`${data.nickName}:${data.message}`);
      break;
    case types.p2p:
      if (!data.success) {
        return console.log(`发送失败:${data.message}`);
      }
      console.log(`${data.nickName}对你说:${data.message}`);
      break;
    case types.log:
      console.log(`${data.message}`);
      break;
    default:
      console.log("未知消息类型哦~");
      break;
  }
});

types.js

module.exports = {
  login: 0,
  broadcast: 1,
  p2p: 2,
  log: 3
};

总结

  • 通过net模块建立TCP服务
  • TCP必须建立连接(3次握手)后才能通信
  • socket通信模型
  • 和使用其他node模块(如koa)一样的思路,都是先建立服务(server),指定端口号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1314633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniGUI学习之Cookie

UniApplication.Cookies.SetCookie( const ACookieName: string, const AValue: string, AExpires: TDateTime 0, ASecure: Boolean False, AHTTPOnly: Boolean False, const APath: string / )

Module ‘app‘: platform ‘android-33‘ not found.

目录 一、报错信息 二、解决方法 一、报错信息 Module app: platform android-33 not found. 检查你的应用程序的build.gradle文件中的targetSdkVersion和compileSdkVersion是否正确设置为已安装的Android SDK版本。 确保你的Android Studio已正确安装并配置了所需的Android …

Axure动态面板的使用以及示例分享

目录 一. 什么是动态面板 二. 动态面板教程——以轮播图为例 2.1 创建动态面板 2.2 动态面板自适应大小 2.3 重复状态,将图片导入 2.4 添加交互事件——图片切换 2.5 效果展示 三. 多方式登录示例展示 四. 后台主界面左侧菜单栏示例展示 一. 什么是动态面板…

如何用Python实现量化交易?

Python是一种广泛使用的编程语言,它的语法简洁易学,而且有着丰富的库和工具,使得Python成为一种非常适合初学者和开发人员使用的语言。 Python量化是指使用Python编程语言进行量化投资研究和分析的过程。量化投资是一种基于数据和统计模型的…

scipy.signal.hilbert和scipy.fftpack.hilbert的区别

提示:分析scipy.signal.hilbert和scipy.fftpack.hilbert在应用的区别 一、代码 import matplotlib import matplotlib.pyplot as plt import numpy as np from pyhht import EMD from scipy.signal import hilbert import tftb.processing from scipy import signa…

DevOps云原生创建devops流水线(微服务项目上传git,打包镜像,部署k8s)

开发和运维人员的解决方案 一、中间件的部署(Sentinel/MongoDB/MySQL) 二、创建DevOps工程 邀请成员 三、创建流水线 四、编辑流水线 ①、拉取代码(若失败,则将制定容器改为maven) 若失败,则将命令改…

在 Spring Boot 中发送邮件简单实现

Spring Boot 对于发送邮件这种常用功能也提供了开箱即用的 Starter:spring-boot-starter-mail。 通过这个 starter,只需要简单的几行配置就可以在 Spring Boot 中实现邮件发送,可用于发送验证码、账户激活等等业务场景。 本文将通过实际的案…

vue中使用ailwind css

官网地址: 安装 - Tailwind CSS 中文网 推荐一个网站,里面可以查询所有的TailWindCSS的class样式: Tailwind CSS Cheat Sheet npm安装: 注意:1、这里要用npm,不要用cnpm。2、最好用install,不要…

手动添加Git Bash Here到右键菜单(超详细)

通过WindowsR快捷键可以打开“运行窗口”,在“窗口”中输入“regedit”,点击“确定”打开注册表。 依次进入HKEY_CLASSES_ROOT —-》 Directory —-》Background —-》 shell 路径为Computer\HKEY_CLASSES_ROOT\Directory\Background\shell 3.在“s…

overleaf 加载pdf格式的矢量图时,visio 图片保存为pdf格式,如何确保pdf页面大小和图片一致

Overleaf支持多种矢量图形格式,其中一些常见的包括: PDF(Portable Document Format): PDF是一种常见的矢量图形格式,Overleaf可以直接加载和显示PDF文件。许多绘图工具和LaTeX生成的图形都可以导出为PDF格式…

02-MQ入门之RabbitMQ简单概念说明

二:RabbitMQ 介绍 1.RabbitMQ的概念 RabbitMQ 是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按…

PythonGame图形绘制函数详解

文章目录 五种图形矩形圆形 五种图形 除了直线之外,pygame中提供了多种图形绘制函数,除了必要的绘图窗口、颜色以及放在最后的线条宽度之外,它们的参数如下表所示 函数图形参数/类型rect矩形Rectellipse椭圆Rectarc椭圆弧Rect, st, edcircl…

uniGUI之上传文件UniFileUploadButton

TUniFileUploadButton主要属性: Filter: 文件类型过滤,有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸; Message:标题以及消息文本,可翻译成中文 TUniFileUploadButton控件 支持多…

Kafka-Kafka基本原理与集群快速搭建(实践)

Kafka单机搭建 下载Kafka Apache Download Mirrors 解压 tar -zxvf kafka_2.12-3.4.0.tgz -C /usr/local/src/software/kafkakafka内部bin目录下有个内置的zookeeper(用于单机) 启动zookeeper(在后台启动) nohup bin/zookeeper-server-start.sh conf…

HTML5+CSS3小实例:萤火虫动画效果

目录 一、运行效果 GIF效果 二、项目概述 三、开发环境 四、实现步骤及代码 1.创建空文件夹 2.完成页面内容 3.完成css样式 五、项目总结 六、源码获取 一、运行效果 GIF效果 二、项目概述 本项目是一个基于HTML和CSS的网页动画效果,展示了一个萤火虫的…

微服务保护--线程隔离(舱壁模式)

一、线程隔离的实现方式 线程隔离有两种方式实现: 线程池隔离 信号量隔离(Sentinel默认采用) 如图: 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果 信号量隔离&#xff1a…

Python学习笔记(五):list(列表)、tuple(元组)、str(字符串)、切片、set(集合)、dict(字典、映射)

目录 一、数据容器 1.list(列表) 2.list(列表)的遍历 3.tuple(元组) 4.str(字符串) 5.(序列)的切片 6.set(集合) 7.dict(字典、映射) 二、数据容器对比总结 三、数据容器的通用操作 四、字符串大小比较 一、数据容器 …

Logistic Regression——逻辑回归

1. 为什么需要逻辑回归 在前面学习的线性回归中,我们的预测值都是任意的连续值,例如预测房价。除此之外,还有一个常见的问题就是分类问题,而逻辑回归是一个解决分类问题的模型,其预测值是离散的。 分类问题又包括…

uniGUI学习之UniTreeview

UniTreeview中能改变一级目录的字体和颜色 function beforeInit(sender, config) { ID"#"config.id; Ext.util.CSS.createStyleSheet( ${ID} .x-tree-node-text{color:green;font-weight:800;} ${ID} .x-tree-elbow-line ~ span{color:black;font-weight:400;} ); }

通义千问 Qwen-72B-Chat在PAI-DSW的微调推理实践

01 引言 通义千问-72B(Qwen-72B)是阿里云研发的通义千问大模型系列的720亿参数规模模型。Qwen-72B的预训练数据类型多样、覆盖广泛,包括大量网络文本、专业书籍、代码等。Qwen-72B-Chat是在Qwen-72B的基础上,使用对齐机制打造的…