介绍了原生websocket的使用,接着学习使用socket.io:
socket.io 是基于 WebSocket 的 C-S 实时通信库,底层是 engine.io,这个库实现了跨平台的双向通信。
engine.io 使用了 WebSocket 和 XMLHttprequest(或JSONP) 封装了一套自己的 Socket 协议(暂时叫 EIO Socket),在低版本浏览器里面使用长轮询替代 WebSocket。一个完整的 EIO Socket 包括多个 XHR 和 WebSocket 连接.
常用api:
socket.emit
数据传输对象为当前socket对应的client,其他各个client socket互相不影响;
socket.broadcast.emit
数据传输对象为所有client,排除当前socket对应的client;
io.sockets.emit
数据传输对象为所有client,包括触发当前事件的client;
使用:
1.安装express,聊天室需要局域网的呀,局域网需要启动http服务呀,所以安装express;
2.安装socket.io,cnpm i --save socket.io 装好后它分为前端、后端两部分,前端页面引入:<script src="/socket.io/socket.io.js"></script>(在文件中看不到,等连接服务的时候就会出现),会自动生成一个文件夹名字就叫socket.io,以及文件夹内生成socket.io.js文件
3.创建mainjs文件,开始撸:
直接贴出写好的代码了:
mainjs:
var express = require("express");
var app = express();
//因为socket.io依赖原生http服务,所以要引入原生http模块,并且调用它的Server()方法将app传入,这样原生的http就拥有了express的方法
var http = require("http").Server(app);
var socket = require("socket.io")(http);//传入http执行socket函数,这样socket就跟http具有同一个端口了
http.listen(9999);
app.use(express.static("./html"));//设置静态资源路径
// 创建socket监听服务:
socket.on("connection", function(ws){
ws.on("diyLogin", function(val){//定义一个完全自定义事件,用来获取前端发来的登录的用户名
var address = ws.handshake.address;
console.log(address);
var u = checkUser(val);
if(u.err){
ws.emit("exist", u);
}else{
socket.sockets.emit("allLogin", u);//执行前端事件,发送范围为每一个在线的客户端
}
});
ws.on("sendMsg", function(msgObj){
socket.sockets.emit("accept", msgObj);//把接收到的某个用户消息发送到所有客户端
})
})
var arr = [];
function checkUser(u){//检测用户名是否已存在
if(arr.length === 0){
arr.push(u);
return u;
};
for(var i = 0; i < arr.length; i++){
if(arr[i] === u){
return {
err: "用户名已存在",
users: arr
}
}
}
arr.push(u);
return u;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
i{
font-style: normal;
}
.chatList{
height: 200px;
border: 1px dashed green;
overflow-y: auto;
}
.myself{
text-align: right;
color: red;
}
i.lin{
font-weight: bold;
color: #ffcc01;
font-size: 16px;
}
i.other{
color: green;
}
p.me{
text-align: right;
color: orange;
}
</style>
</head>
<body>
<div class="container">
<div class="loginBox">
<input type="text" class="form-control" id="username">
<button class="btn" id="sure">登录</button>
</div>
<div class="chatBox hidden">
<div class="chatList">
</div>
<textarea class="form-control" id="msg" cols="30" rows="5"></textarea>
<button class="btn" id="send">发送</button>
<div class="alert alert-success hidden" role="alert"></div>
</div>
</div>
</body>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
//链接socket
var ws = io.connect("ws://localhost:9999");
var user;
$("#sure").click(function(){
var name = $("#username").val();
if(!name){
alert("好歹起个名呀,eg:李易峰");
}else{
//通知后台有人登陆了,socket.io都是基于事件的,要做的操作都是触发自定义事件的方式
ws.emit("diyLogin", name);//执行自定义事件传入用户名
user = name;//把当前用户名称保存到全局变量
}
})
//获取后端返回的用户是否存在的查询结果
ws.on("exist", function(re){
if(re.err){
alert(re.err);
console.log("已经登陆的用户:\n", re.users)
return;
}
})
//接收后端返回的全局的登录者的名字的事件
ws.on("allLogin", function(name){
var _alert = name === "赵治林" ? "欢迎 男爵 <i class='lin'>"+name+"</i> 骑着火麒麟来到了本直播间!" : "<i class='other'>"+name+" </i>进入直播间";
$(".alert").html(_alert).removeClass("hidden").show();
$(".loginBox").hide();//登陆后隐藏登录盒子
$(".chatBox").removeClass("hidden");//显示出聊天界面
setTimeout(function(){
$(".alert").fadeOut(function(){
$(this).addClass("hidden");
});
}, 1500)
})
//发送聊天消息
$("#send").click(function(){
var msg = $("#msg").val();
if(!msg){
alert("空消息也要钱哦!");
}else{
ws.emit("sendMsg", {msg, user});//执行事件把内容和发送者发送给后台,让后台返回给所有客户端
$("#msg").val("");
}
})
//接收聊天消息
ws.on("accept", function(o){
var p = $(`<p>${o.user}: ${o.msg}</p>`)
if(o.user === user){
p.addClass("me");
}
$(".chatList").append(p).scrollTop($(".chatList")[0].scrollHeight);
})
</script>
</html>
个人理解:
socket.io实现了一对多的B-S双向通信,是基于事件驱动的,相当于后台自定义一个事件,前端触发,前端自定义一个事件,后台触发,同时可以选择socket.io提供的方法指定数据发送的范围,比如发给哪一个客户端;