前端小Demo:使用Socket实现简易网络聊天室

Posted 我是真的不会前端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端小Demo:使用Socket实现简易网络聊天室相关的知识,希望对你有一定的参考价值。

项目实现截图

在这里插入图片描述

1.实现原理

websocket

首先我们要知道 http是一种无状态协议,无法轻松实现实时应用。服务器只会响应来自客户端的请求,但是它与客户端之间不具备持续连接。我们可以实现捕获浏览器上的事件,通过事件跟服务器进行数据交互,使用ajax技术。但是反过来却不可能实现:服务器发生了一个事件,服务器不会主动去跟客户端交互。你们想一想,如果有一天百度像你发送了一个请求,会不会觉得很诡异。

可是聊天室确实存在。聊天室是要保持客户端和服务器持续连接,且服务器能主动给客户端发送消息,实现方式如下:

长轮询:

客户端每隔很短的时间,当时通过setinterval每隔多少秒都会对服务器发出请求,查看是否有新的消息,只要轮询速度足够快,就能给人造成交互是实时进行的感觉。这种做法实属无奈,实际上会对服务器、客户端双方都造成了大量的性能浪费。

长连接:

客户端跟服务器连接一次,连接上之后就不断开,服务器不给客户端响应,服务器有了新数据就将数据发回去,又有了新数据,就将数据发回来,而一直保持阻塞状态。这种做法也会造成大量的性能浪费。
H5提供了一个新技术解决这些问题:websocket
websocket协议能够让浏览器和服务器进行全双工实时通信,全双工就是互相之间都能主动发送消息了,服务器也能主动给客户端发送消息。

websocket的原理:

利用http请求产生握手,http头部中含有websocket协议的请求,所以握手之后,二者转用tcp协议进行交流,tcp是一个比较底层的协议,可以实现实时通信。现在的qq使用的就是这个协议。
所以websocket协议需要浏览器支持,也需要服务器支持。
支持websocket协议的浏览器:Chrome4、FireFox4、Safari5
支持websocket协议的服务器:Node0、Apache7.0.2、nginx1.3
可以看出,nodejs天生就支持websocket协议,但是从底层一步一步搭建nodejs服务器来处理tcp协议的工程是很庞大的,所以现在有一个通用的第三方模块来处理websocket - socket.io

socket.io

如何下载

npm i socket.io -S

官网

http://socket.io/

2.socket搭建

搭建一个聊天室:

1.创建一个web服务器

const http = require('http')
const server = http.createServer((req,res)=>{
    res.setHeader('content-type','text/html;charset=utf8')
    res.end("这是web服务器")
})
server.listen(3000)

2.接下来导入socket.io

并通过socket.io将web服务器转换成一个长连接服务器,且将客户端需要一个js文件路径暴露出去:

const socketIO = require('socket.io')

const io = socketIO(server)

此时,我们通过服务器就能访问到一个地址:http://locahost:3000/socket.io/socket.io.js,最终能响应得到一个js文件地址。

客户端通过这个地址就能跟服务器进行即时通信了。

客户端代码:

<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io()
</script>

3.有关socket对象

客户端导入的这个js文件中,暴露了io函数,调用得到一个socket对象。

socket其实一个套接字,类似于插座,此时服务器有一个插座,客户端有一个插头,只要能将两边连接在一起就能进行通信了。

得到的socket这个套接字对象,他的使用方法是使用事件的机制:

socket对象有一个emit方法,用来触发事件 - 发送消息

socket对象有一个on方法,来绑定事件 - 监听是否消息接收到

// 接收消息
socket.on('message',message=>{
    // 监听message事件,只要对方触发了message事件,message就是对方发送过来的数据
    console.log(message)
})
// 发送消息
socket.emit('send',数据) // 表示触发了事件send,并在触发事件的时候将数据传送了过去

4.服务器的操作:

我们创建好的io对象需要绑定一个固定的事件 - connection,如果有客户端连接过来,就会触发这个事件

io.on('connection',socket=>{
    // 有客户端连接来,会得到一个socket对象,这个socket跟客户端的socket是同一个,就表示插头和插座连接在一起了,所有这个socket也可以进行绑定事件和触发事件
    // 通信
    socket.emit('message',数据)
    
    socket.on('send',数据)
})

上面的message事件和send事件都是自定义的,不是固定的,且客户端和服务器进行交互的时候,使用的都是js,所以他们之间进行交互的数据,只要符合js的数据类型就能进行,比如字符串、数字、对象、数组 。。。

此时只是实现了一个客户端和一个服务器之间的即时通信,如果要多个客户端和一个服务器进行通信的话,还需要服务器将数据进行广播:

io.emit('message',数据) 

服务器进行相应的时候,不能只用socket进行发送数据,需要使用io,就代表所有客户端了。

3.项目代码

服务器模块

这里需要创建nodejs服务器,导入socket.io模块 暴露websocket函数

// 1.创建http服务器 - websocket是隐藏在http请求中的
const http = require('http')
const fs = require('fs')
const server = http.createServer((req,res)=>{
    let url = req.url;
    if(url === '/'){
        let data = fs.readFileSync('index.html')
        res.end(data)
    }
})
// 2.导入socket.io模块
const socketIo = require('socket.io')
// 3.将websocket暴露出来
const io = socketIo(server) // 将web服务器当做参数传进去
// 有了这行代码,就暴露有一个js文件的地址:/socket.io/socket.io.js - 用于个客户端使用的
// io这个对象可以绑定一个connect事件,表示有客户端连接过来
io.on('connect',function(socket){ // 这里的socket其实跟客户端使用的socket是同一个socket
    // socket可以用来接收客户端的请求 - 监听指定的事件名称
    socket.on('fasong',function(message){ // message其实就是客户端发送过来的消息
        // 接收到任意一个客户端发来的消息 - 需要将消息进行广播 - 给所有客户端发送消息
        // 使用io来触发事件,就是在广播消息
        io.emit('send',message)
    })
    // 服务器也可以给客户端发消息 - 给刚刚发消息过来的客户单回复消息
})
server.listen(3000)

创建socket服务端

原理

通过登入,保存用户名到coockie。如果url是/login。响应登入页面。设置两小时coockie时间。发现coockie存在 响应聊天界面。获取coockie响应对方的用户名,发送一个对象进去:其中包括username msg id:socket id

代码

const http = require('http')
const fs = require('fs')
// 获取cookie的方法
let getCookie = (cookies,key)=>{
    let arr = cookies.split('; ')
    for(let i=0;i<arr.length;i++){
        let brr = arr[i].split('=')
        if(brr[0] === key){
            return brr[1]
        }
    }
}
const server = http.createServer((req,res)=>{
    let url = req.url;
    // 判断用户是否登录
    // req.headers.cookie
    if(url === '/'){
        if(req.headers.cookie){
            let username = getCookie(req.headers.cookie,'username')
            if(!username){
                url = '/login'
            }else{
                let data = fs.readFileSync('./client.html')
                res.end(data)
            }
        }else{
            url = '/login'
        }
    }
    if(url === '/login'){
        let data = fs.readFileSync('./login.html')
        res.end(data)
    }
})
// 导入socket.io
const socketIo = require('socket.io')
const io = socketIo(server)
// 监听连接
io.on('connection',function(socket){
    // 接收socket的消息
    socket.on('request',function(res){
        let {message,username} = res
        // 广播消息
        io.emit('response',{
            id:socket.id,
            message,
            username
        })
    })
})
// 监听端口
server.listen(3000)

客户端界面

登入界面

代码

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>document</title>
</head>
<body>
<form action="/logHandler" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td>
                <input type="text" name="username">
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="submit">
            </td>
        </tr>
    </table>
</form>
</body>
<script>
document.querySelector('form').onsubmit = function(){
    // 设置cookie
    let date = new Date()
    date.setTime(date.getTime()-6*3600*1000)
    document.cookie = 'username='+document.querySelector('[name="username"]').value+";expires="+date+";path=/"
    location.href = "/"
    return false;
}
</script>
</html>

聊天界面

代码

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>document</title>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<textarea name="message" cols="30" rows="10"></textarea>
</body>
<script>
// 发送http包含websocket的请求
// 引入了js文件后,js文件给全局暴露了一个函数 - io
// console.log(io);
// 调用这个函数
let socket = io()
// console.log(socket);
// 调用得到的socket对象,可以个服务器发送消息,也可以接收服务器发过来的消息
// 客户端发消息 - socket.emit(指定事件名,数据)
// socket.emit('fasong','你好啊')

// 发消息放在回车事件中
let textarea = document.querySelector('[name="message"]')
textarea.onkeydown = function(e){
    e = e || window.event;
    let keycode = e.keyCode || e.which;
    if(keycode === 13){
        socket.emit('fasong',this.value)
    }
}
// 客户端可以监听服务器发来的消息
socket.on('send',function(message){
    console.log(message);
})
</script>
</html>

4.完整项目代码

gitee项目源码

5.如何使用

npm 一键安装组件

拉下来后再所在文件夹打开cmd 命令行输入 npm i 如果报错就使用cnpm i
相关组件安装完成后
然后输入
在这里插入图片描述

安装nodemon

命令行输入以下代码

npm i nodemon

nodemon 打开项目

输入

nodemon .\\server.js

在这里插入图片描述

浏览器地址栏输入localhost:3000/

效果

进入登入界面随便输入一个用户名
这里以张三李四举例

A浏览器

在这里插入图片描述

B浏览器

在这里插入图片描述

以上是关于前端小Demo:使用Socket实现简易网络聊天室的主要内容,如果未能解决你的问题,请参考以下文章

《基于Node.js实现简易聊天室系列之总结》

第94题JAVA高级技术-网络编程13(简易聊天室8:使用Socket传递图片)

第95题JAVA高级技术-网络编程14(简易聊天室9:使用Socket传递音频)

第92题JAVA高级技术-网络编程11(简易聊天室6:使用Socket通信)

第92题JAVA高级技术-网络编程11(简易聊天室6:使用Socket通信)

C 基于UDP实现一个简易的聊天室