基本原理
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议(这段是我从 Runoob 上摘的)。它的使用比较简单,在客户端只需要new WebSocket(url)
对象,即可使用。
这么说可能有些抽象,简单来说,就是通过一次 HTTP 握手,就可以在服务端和客户端之间建立一个通道,进行实时的信息传输,无需轮询。
[ HTTP ]
[客户端] [服务器]
| |
|--------------------->|
| 请求 |
| |
|<---------------------|
| 响应 |
| |
| |
|--------------------->|
| 请求 |
| |
|<---------------------|
| 响应 |
| |
| |
[ WebSocket ]
[客户端] [服务器]
| |
|--------------------->|
| 握手 |
| |
|<---------------------|
| 告诉客户端已收到 |
| |
|<-------------------->|
| 双向的往来消息 |
|<-------------------->|
| |
| |
|----------------------|
| 关闭连接 |
那既然有了HTTP,要用WebSocket是要有一定的原因的,问题就在于HTTP是单向的(客户端请求、服务器响应),服务器是无法主动给客户端发送消息的,如果要实现如聊天室,只能通过资源、带宽消耗较大的轮询等方式进行实现,在这样的情况下,WebSocket就出现了。下面是一个利用WebSocket制作实时聊天室的例子。
例子
首先先设计一下实现方式,我的设想是这样的:客户端发送消息,就告诉服务器这段消息的内容、时间和发送者,服务器收到后向所有人广播这条消息,这样所有人就得到了这位发送的消息。
首先写一个服务端的程序,这里使用nodejs
的nodejs-websocket
库,先写出引入依赖和创建服务器对象。
var ws = require("nodejs-websocket") //添加Nodejs-WebSocket依赖
var port = 8001
var server=ws.createServer(function(conn){ //创建一个WebSocket服务器!
}).listen(port) //设置服务器开启的端口
然后根据刚才的设计,应该在收到消息发送者的内容的时候,把这个消息广播给所有人,那么应该在收到消息后直接再广播出去,使用了conn.sendText()
函数,然后通过服务器server
对象的connections
属性,给每个连接者都发送刚才发送者发送的消息:
var ws = require("nodejs-websocket") //添加Nodejs-WebSocket依赖
var port = 8001
var server=ws.createServer(function(conn){ //创建一个WebSocket服务器!
conn.on("text", function (str) { //监听收到消息事件(名为"text")
server.connections.forEach(function (conn) { //给每个连接的人都执行这个操作
conn.sendText(str) //给这个人发送刚才的消息
})
console.log("收到消息:",str) //控制台输出刚刚消息的内容
})
}).listen(port) //设置服务器开启的端口
最后添加一个输出服务器开设的ip及端口的功能,最终代码如下:
var ws = require("nodejs-websocket") //添加Nodejs-WebSocket依赖
var port = 8001
console.log("你的服务器的地址是:ws://"+getIP()+":"+port+",快让你的朋友们进入聊天室吧")
var server=ws.createServer(function(conn){ //创建一个WebSocket服务器!
conn.on("text", function (str) { //监听收到消息事件(名为"text")
server.connections.forEach(function (conn) { //给每个连接的人都执行这个操作
conn.sendText(str) //给这个人发送刚才的消息
})
console.log("收到消息:",str) //控制台输出刚刚消息的内容
})
}).listen(port) //设置服务器开启的端口
//以下代码为获取电脑内网IP
function getIP(){
var os=require("os") //引入OS依赖
return os.networkInterfaces()['WLAN'][1].address //返回Network信息中的内网IP
}
现在这样一个简易的服务器部分就完成了,服务端代码请见本章节最下方。
然后进行一个客户端前端页面的编写:
<div id="Output" style="width:100%;height:50%;border:2px solid black;border-radius:4px;margin-top:10px;"></div>
<div style="margin-top:10px;">
<input type="text" id="Input" style="position:absolute;width:90%;height:20%;">
<button style="position:absolute;right:5px;width:10%;height:20%;"onclick="sendmessage()">发送</button>
</div>
<div style="position:absolute;bottom:10px;">
<b>连接到聊天室</b><br/>
聊天室地址 <input type="text" id="ServerLink"/>
聊天室昵称 <input type="text" id="MyName"/>
<button onclick="connect()">连接</button>
</div>
然后进行客户端的接收、发送消息核心制作:
var Socket;
function connect(){
var serverlink=document.getElementById("ServerLink").value;
var myname=document.getElementById("MyName").value;
var output=document.getElementById("Output");
Socket = new WebSocket(serverlink);
Socket.onopen = function()
{
output.innerHTML+="<b style='color:green'>成功连接到服务器!</b>";
};
Socket.onmessage = function (evt)
{
console.log(evt);
var data=JSON.parse(evt.data);
output.innerHTML+="<b>"+data.name+"</b> >> <b>"+data.message+"</b><br/>";
};
}
function sendmessage(){
var input=document.getElementById("Input").value;
var myname=document.getElementById("MyName").value;
var date=new Date();
var data={};
data.time=date.getHours()+":"+date.getMinutes();
data.name=myname;
data.message=input;
Socket.send(JSON.stringify(data));
return;
}
window.onbeforeunload = function(evt) {
Socket.close();
}//关闭窗口前先关闭连接,否则服务器会报错
最后可以试试效果,比较神奇的,使用了大概70行左右就完成了一个完备的聊天室。
实例代码
./index.html(客户端)
<html>
<head>
</head>
<body>
<div id="Output" style="width:100%;height:50%;border:2px solid black;border-radius:4px;margin-top:10px;"></div>
<div style="margin-top:10px;">
<input type="text" id="Input" style="position:absolute;width:90%;height:20%;">
<button style="position:absolute;right:5px;width:10%;height:20%;"onclick="sendmessage()">发送</button>
</div>
<div style="position:absolute;bottom:10px;">
<b>连接到聊天室</b><br/>
聊天室地址 <input type="text" id="ServerLink"/>
聊天室昵称 <input type="text" id="MyName"/>
<button onclick="connect()">连接</button>
</div>
<script>
var Socket;
function connect(){
var serverlink=document.getElementById("ServerLink").value;
var myname=document.getElementById("MyName").value;
var output=document.getElementById("Output");
Socket = new WebSocket(serverlink);
Socket.onopen = function()
{
output.innerHTML+="<b style='color:green'>成功连接到服务器!</b><br/>";
};
Socket.onmessage = function (evt)
{
console.log(evt);
var data=JSON.parse(evt.data);
output.innerHTML+="<b>"+data.name+"</b> >> <b>"+data.message+"</b><br/>";
};
}
function sendmessage(){
var input=document.getElementById("Input").value;
var myname=document.getElementById("MyName").value;
var date=new Date();
var data={};
data.time=date.getHours()+":"+date.getMinutes();
data.name=myname;
data.message=input;
Socket.send(JSON.stringify(data));
return;
}
window.onbeforeunload = function(evt) {
Socket.close();
}//关闭窗口前先关闭连接,否则服务器会炸
</script>
</body>
</html>
./WS.js(服务端)
var ws = require("nodejs-websocket") //添加Nodejs-WebSocket依赖
var port = 8001
console.log("你的服务器的地址是:ws://"+getIP()+":"+port+",快让你的朋友们进入聊天室吧")
var server=ws.createServer(function(conn){ //创建一个WebSocket服务器!
conn.on("text", function (str) { //监听收到消息事件(名为"text")
server.connections.forEach(function (conn) { //给每个连接的人都执行这个操作(server对象的connections进行foreach操作)
conn.sendText(str) //给这个人发送刚才的消息
})
console.log("收到消息:",str) //控制台输出刚刚消息的内容
})
}).listen(port) //设置服务器开启的端口
//以下代码为获取电脑内网IP
function getIP(){
var os=require("os") //引入OS依赖
return os.networkInterfaces()['WLAN'][1].address //返回Network信息中的内网IP
}
[^WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。]: 摘自Runoob HTML5 Websocket