node.js阶段 - 了解实时通讯原理(网页版聊天)

模拟实时通讯

实现方式:前端轮循 、SSE服务器推送数据 、websocket协议 、socket.io
同源策略:协议,域名,端口号一致

前端轮循

前端以 ajax 的方式,循环定时获取数据(实质上也是单工通讯)
缺点 : 消耗性能,消耗资源

前端核心JS代码

jQuery实现 ajax请求

	<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
	<script>
	    // 使用jq中的ajax发送请求,获取最新的数据
	    function anser(){ 
	    	// 接收后端发送的数据
	        $.ajax({
	            url:"/getData",
	            success(res){
	                // 请求+响应 成功后,执行的方法(success,名字为固定的)
	                // console.log("请求数据" + res)
	                let str = "";
	                res.forEach(item => {
	                    str += `<li class="chat-left">${item.userName}:${item.content}</li>`    
	                });
	                document.querySelector(".chat-show").innerHTML = str;
	                document.querySelector(".chat-show").scrollTop = 1000;
	            }
	        });
	    }
	
	    // 轮询 不停地发送请求
	    setInterval(()=>{
	    	anser();
	    },1000)
	    
	    // 发送数据给后端
	    // 聊天框的消息发送按钮
	    document.querySelector(".input-text button").onclick = function(){
	        //            文本输入框的信息
	        let content = $(".input-frame").val();
	        $.ajax({
	            url:"/addChat",
	            method:"post",//请求的方式 get post
	            data:{
	                content
	            },
	            success(res){
	                if (res.status === 1) {
	                    anser();
	                }else{
	                    console.log(res);
	                }
	            }
	        });
	    }
	</script>
	
后端服务器核心代码

	// 返还数据库中的数据
	router.get("/getData",async ctx=>{
	    let [data] = await connection.promise().query("SELECT * FROM chat");
	    // console.log("服务器端的" + data)
	    ctx.body = data;
	})
	
	// 数据接收并保存到数据库
	router.post("/addChat",async ctx=>{
	    // console.log(ctx.request.body)
	    let {content} = ctx.request.body;
	    let sql = "INSERT INTO chat(content) VALUES (?)";
	    let result = await connection.promise().query(sql,[content]);
	
	    let info;
	    if (result[0].affectedRows > 0) {
	        info = {
	            message:"添加成功",
	            status:1
	        }
	    }else{
	        info = {
	            message:"添加失败",
	            status:0
	        }  
	    }
	    ctx.body = info;
	})
	

SSE服务器推送数据

单工通讯,单方面工作
服务端推送数据,不能停止推送

后端服务器核心代码

	const http = require("http");
	const fs = require("fs");
	const url = require("url");
	
	let server = http.createServer((req,res)=>{
	
	    let urlObj = url.parse(req.url,true);
	
	    if (urlObj.pathname === "/" || urlObj.pathname === "/index") {
	        // 加载页面
	        let resData = fs.readFileSync("./index.html");
	        // res.write(resData)
	        res.end(resData)
	    }else if(urlObj.pathname === "/sse"){
	        // 推送数据
	        // 1. 设置文件头
	        res.setHeader("content-type","text/event-stream")
	        setInterval(()=>{
	            // 2.官方要求 声明数据开头 结尾   
	            // 不写的情况下 有可能会显示
	            let obj = {
	                name:"Ding",
	                age:20
	            }
	            res.write("data:" + JSON.stringify(obj) + "\r\n\r\n");
	        },1000)
	    }
	})
	server.listen(7692)

前端核心JS代码

	// 接受指定路径下的数据 
	let source = new EventSource("/sse");
	
	source.onopen =function(){
		console.log("链接已建立");
	}
        
	// 服务器端的推送数据接收
	source.onmessage = function(d){
		console.log(d);
	}
        
	// 服务器端的错误信息接收 
	source.error = function(err){
		console.log(err);
	}
	

websocket 协议

综合上面所述 两种传讯方式

后端服务器核心

	let WebSocketServer = require("ws").Server;
	let wss = new WebSocketServer({port:6991}); // => 端口号
	const mysql = require("mysql2");
	// 链接数据库
	const connection = mysql.createConnection({
	    host: "localhost",
	    user: "root",
	    password: "123123",
	    database: "my_try",
	    charset: "utf8"
	})
	// 开启服务
	wss.on("connection",function(ws){
	    let sql = 'SELECT * FROM chat';	
	    // 推送数据
	    setInterval(()=>{
	        connection.query(sql, function (err, result) {
	            ws.send(JSON.stringify(result))
	        });
	    },1000)
	    
	    // 错误信息
	    ws.onerror = function(){
	    
	    }
	    // 接收数据
	    ws.onmessage = function(pageObj){
	        let pageData = JSON.parse(pageObj.data)
	        let pageSql = "INSERT INTO chat(content,userName) VALUES (?,?)";
	        connection.query(pageSql, [pageData.content,pageData.thisName]);
	    } 
	    // 关闭服务
	    // ws.close()
	})
	
前端JS核心代码
    // 链接服务器 
    let ws = new WebSocket("ws://localhost:6991");
    // 建立连接
    ws.onopen=function(){
        console.log("链接已建立");
    }
	// 接收并渲染页面
    ws.onmessage = function(result){
        let data = JSON.parse(result.data)
        let str = "";
        for (let i = 0; i < data.length; i++) {
            if (data[i].userName == "Mr_Qin") {
                str += `<li class="chat-left">${data[i].userName}&emsp;${data[i].content}</li>`
            } else {
                str += `<li class="chat-right">${data[i].content}&emsp;${data[i].userName}</li>`
            }
        }
        document.querySelector(".chat-show").innerHTML = str;
        document.querySelector(".chat-show").scrollTop = 1000;
    }
	// 发送信息
    document.querySelector(".input-text button").onclick = function () {
        let content = $(".input-frame").val();
        let thisName = "Mr_Ding";
        let sendData = JSON.stringify({content,thisName})
        ws.send(sendData)
    }


socket.io

node.js 使用socket.io 模块实现长连接
双工通信; 封装取来的模块非原生;
前端、后端都要引入模块,只是方式不同

后端服务器核心

	const Koa = require("koa");
	const Router = require("koa-router");
	const static = require("koa-static");
	let app =new Koa();
	let router = new Router();
	
	app.use(static(__dirname + "/static"));
	router.get("/text",ctx => {
	    ctx.body = "hello";
	})
	
	const server = require("http").createServer(app.callback());
	const io = require("socket.io")(server); // => 需要下载 socket.io 模块	
	io.on("connection",(socket)=>{
	    console.log("连接初始化")
	    let obj = {
	        name:"王",
	        age:20
	    }
	    setInterval(()=>{
	        // 传递数据 
	        //          自定义事件, 携带数据
	        socket.emit("getData",obj);
	
	    },1000)
		// socket 代表当前连接者
	    socket.on("addData",(data)=>{ // 监听addData 方法,如果被触发 则执行函数
	        console.log(data)
	        // 当前连接者可使用
	        socket.emit("getData",data); // 自定义getData 方法, 传递数据 data	
	        // broadcast:除当前连接者以外的所有连接者
	        socket.broadcast.emit("getData",data)
	    })
	})
	
	app.use(router.routes());
	server.listen(7979);

前端JS核心代码
	<script src="./socket.io.js"></script>
	// 客户端建立连接
	let socket = io.connect("/");
	// 监听 getData 触发后,执行功能
	socket.on("getData",(data)=>{
		console.log(data)
		document.querySelector(".s").innerHTML = data;
	})

	document.querySelector(".btn").onclick = function(){
		let inputTxt = document.querySelector(".ipt").value;
		socket.emit("addData",inputTxt); // 自定义 addData 功能, 携带参数 inputText
	}
	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值