介绍
通常我们web使用的是http协议,但是 HTTP 协议有一个缺陷:通信只能由客户端发起。
所以我们需要一个可以由服务端主动发出的协议,即WebSocket。
WebSocket是HTML5新增的一种通信协议,其特点是服务端可以主动向客户端推送信息,客户端也可以主动向服务端发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
Socket.IO 是一个基于 Node.js 的实时应用程序框架,在即时通讯、通知与消息推送,实时分析等场景中有较为广泛的应用。
socket.io 包含两个部分:
- 服务器端(server):运行在 Node.js 服务器上
- 客户端(client):运行在浏览器中
搭建步骤
- 首先,让我们创建一个package.json描述我们项目的清单文件。
执行:npm init -y
生成package.json文件
{
"name": "aaa",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies":{}
}
- 下面,为dependencies用我们需要的东西填充属性,我们将使用npm install:
npm install express --save
- 安装完成后,我们可以创建一个index.js文件来设置我们的应用程序。
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/www'));
app.listen(3000, () => console.log('Example app listening on port 3000!'))
这意味着:
- Express初始化app为可以提供给HTTP服务器的函数处理程序
- 我们定义了一个路由处理程序/,当我们访问我们的网站主页时会被调用。
- 我们使http服务器在端口3000上侦听。
- 创建静态资源 www/index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.chat {
float: left;
padding: 1em 1em 0 2em;
height: 100%;
width: 500px;
border-right: 1px solid #DA4;
overflow-y: scroll;
}
.inputpart {
float: left;
margin-left: 10px;
}
#userName {
font-size: 20px;
color: rgb(3, 57, 109);
}
</style>
</head>
<body>
<div class="chat">
<ul id="messages">
//聊天信息
</ul>
</div>
<div class="inputpart">
<div id="userName">
//用来展示用户id
</div>
<div action="" id='logForm'>
<input type="text" id='inpU'>
<button id='login'>登陆</button>
</div>
<div id='chatForm' style='display: none;'>
<input autocomplete="off" id="inpB" /><button id="say">Send</button>
</div>
</div>
</body>
</html>
此时开启服务: node index, 访问 localhost:3000。就能看到页面了。
5. 安装:socket.io
npm install socket.io --save
这将安装模块并将依赖项添加到中package.json
6. 然后在index.js中注册socket.io,并改为http监听:
const express=require('express')
const app = express();
let http = require('http').Server(app)
// socket.io作为一个函数,当前http作为参数传入生成一个io对象?
// io-server
const io = require('socket.io')(http)
app.use(express.static(__dirname + '/www'));
io.on('connection', (socket) => {
console.log('a user connected');
});
http.listen(3000, () => console.log('Example app listening on port 3000!'))
此时服务已改为WebSocket服务。
这段代码中,connection
事件在客户端成功连接到服务端时触发,有了这个事件,我们可以随时掌握用户连接到服务端的信息。
- 数据传输
服务端运行后会在根目录动态生成socket.io的客户端js文件,客户端可以通过固定路径/socket.io/socket.io.js添加引用。
在HTML中引用js文件,并调用:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
$(function () {
// 连接成功会触发服务器端的connection事件
var socket = io();
})
</script>
- 开启服务: node index, 访问 localhost:3000。尝试打开多个标签,您将看到几条消息。
9. 当客户端成功建立连接时,在connection
事件的回调函数中,我们还是可以为socket
注册一些常用的事件,如:disconnect
事件socket.on(‘disconnect’,function(){…});,它在客户端连接断开时
触发,这时候我就知道用户已经离开了。
扫描二维码关注公众号,回复:
11155827 查看本文章
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
- 然后,如果多次刷新选项卡,则可以看到它的作用。
- 向连接的客户端发消息,Socket.IO向我们提供了该io.emit()方法。
socket.emit('hello', 'can you hear me?', 1, 2, 'abc');
- 给除了本次连接的其他所有连接者广播消息
socket.broadcast.emit('broadcast', 'hello friends!');
前端代码如下:
$(function () {
// 连接成功会触发服务器端的connection事件
// io-client
// 连接成功会触发服务器端的connection事件
var socket = io();
//输入昵称 、登陆
$('#login').on('click',function(e){
if($('#inpU').val().trim()!==''){
socket.emit('login', {
name: $('#inpU').val()
});
}else{
alert('用户名不能为空')
}
})
// 登录成功,隐藏登录模块,显示聊天模块
socket.on('loginSuc', function(){
$('#logForm').hide();
$('#chatForm').show();
})
// 登陆失败
socket.on('loginError', ()=> {
alert('用户名已存在,请重新输入!');
$('#name').val('');
});
//按下回车键发送聊天信息
$('#inpB').keyup((e)=> {
if(e.keyCode == 13) {
sendMessage();
}
});
//点击发送也可以发送消息
$('#say').on('click',function(){
sendMessage();
})
function sendMessage(){
if($('#inpB').val().trim()==''){
alert('请输入内容!');
return false;
}else{
socket.emit('sendMsg', {
msg: $('#inpB').val()
});
$('#inpB').val('');
return false;
}
}
// 接收消息
socket.on('receiveMsg', function(obj){
console.log(obj);
$('#messages').append(`<li>姓名:${obj.name} ${obj.msg}</li>`)
})
})
- 后端代码如下:
var express = require('express'); // 引入express模块
var app=express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var users = []; // 储存登录用户
// 路由为/默认www静态文件夹
app.use('/', express.static(__dirname + '/www'));
io.on('connection', function(socket){ // 用户连接时触发
console.log('a user connected');
// 登录,检测用户名
socket.on('login', function(user){
if(users.indexOf(user.name) > -1) {
socket.emit('loginError');
} else {
users.push(user.name);
socket.nickname = user.name;
socket.emit('loginSuc');
}
})
// 发送消息事件
socket.on('sendMsg', function(data){
socket.broadcast.emit('receiveMsg', {
name: socket.nickname,
msg: data.msg
});
socket.emit('receiveMsg', {
name: socket.nickname,
msg: data.msg
});
});
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
http.listen(4000, function(){ // 监听3000端口
console.log('listening on *:4000');
});