前言

一般来讲,HTTP 是基于文本的“单向”通讯机制。这里所谓的“单向”,乃相对于“双向”而言,因为 HTTP 服务器只需根据请求返还恰当的 HTML 给客户端即可,不涉及客户端向服务端的通讯。这种单向的机制比较简单,对网络质量要求也不高。而更多的场景则是需要可靠、稳定的端到端连接。一般这种服务是实时的、有态的而且是长连接,长连接则暗示两段须达致相向通讯的能力,也就说是服务端客户端两者间能够实时地相互间通信。毫无疑问,能够实时通信的服务器正是我们对服务器基本要求之一。区别于 HTTP 服务器以 HTTP 为通讯协议, 实时服务器一般采用较为底层的 TCP/IP 为协议通讯,实现了“套字节 Socket”的双向机制。
Socket 是根据博克莱 (U.C.Berkley) 大学早期发展的 Socket 概念写成的,其设计理念是是将网络传输类比成文件的读取与写入 (传送的动作被视为是写入/接收的动作被视为是读取),如此、传送与接收就简化为编程人员比较容易懂的 读取与写入,降低了网络编程的学习困难度。
聊天室服务器
聊天室的实时连接基于底层的 TCP 直接连接,为此我们须调用 Node 的 TCP 模块。如果不太熟悉所谓 TCP 网络编程?太底层了是不是?没关系,我也不熟悉,边学边做嘛,只不过千万不必因为遇到陌生的词汇而害怕,其实这样原理并不深奥,而且下面的例子也十分的简单易懂!咱们就从最简单的开始吧,下面代码仅仅十行,它的作用是服务器向客户端输出一段文本,完成 Sever --> Client 的单向通讯。
// Sever --> Client 的单向通讯
var net = require('net');
var chatServer = net.createServer();
chatServer.on('connection', function(client) {
client.write('Hi!\n'); // 服务端向客户端输出信息,使用 write() 方法
client.write('Bye!\n');
client.end(); // 服务端结束该次会话
});
chatServer.listen(9000);
客户端可以是系统自带的 Telnet:
telnet 127.0.0.1 9000
执行 telnet 后,与服务点连接,反馈 Hi! Bye! 的字符,并立刻结束服务端程序终止连接。如果我们要服务端接到到客户端的信息?可以监听 server.data 事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息):
// 在前者的基础上,实现 Client --> Sever 的通讯,如此一来便是双向通讯
var net = require('net');
var chatServer = net.createServer(),
clientList = [];
chatServer.on('connection', function(client) {
// JS 可以为对象自由添加属性。这里我们添加一个 name 的自定义属性,用于表示哪个客户端(客户端的地址+端口为依据)
client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi ' + client.name + '!\n');
clientList.push(client);
client.on('data', function(data) {
broadcast(data, client);// 接受来自客户端的信息
});
});
function broadcast(message, client) {
for(var i=0;i<clientList.length;i+=1) {
if(client !== clientList[i]) {
clientList[i].write(client.name + " says " + message);
}
}
}
chatServer.listen(9000);
这里要说明一下的是,不不同操作系统对端口范围的限制不一样,有可能是随机的。
那么上面是不是一个完整功能的代码呢?我们说还有一个问题没有考虑进去:那就是一旦某个客户端退出,却仍保留在 clientList 里面,这明显是一个空指针(NullPoint)。如果是在这样的话我们写程序太脆弱了,能不能更健壮一些?——请接着看。
首先我们简单地把 client 从数组 clientList 中移除掉。完成这工作一点都不困难。Node TCP API 已经为我们提供了 end 事件,即客户端中止与服务端连接的时候发生。移除 client 对象的代码如下:
chatServer.on('connection', function(client) {
client.name = client.remoteAddress + ':' + client.remotePort
client.write('Hi ' + client.name + '!\n');
clientList.push(client)
client.on('data', function(data) {
broadcast(data, client)
})
client.on('end', function() {
clientList.splice(clientList.indexOf(client), 1); // 删除数组中的制定元素。这是 JS 基本功哦~
})
})
但是我们还不敢说上述代码很健壮,因为一旦 end 没有被触发,异常仍然存在着。下面我们看看解决之道:重写 broadcast():
function broadcast(message, client) {
var cleanup = []
for(var i=0;i<clientList.length;i+=1) {
if(client !== clientList[i]) {
if(clientList[i].writable) { // 先检查 sockets 是否可写
clientList[i].write(client.name + " says " + message)
} else {
cleanup.push(clientList[i]) // 如果不可写,收集起来销毁。销毁之前要 Socket.destroy() 用 API 的方法销毁。
clientList[i].destroy()
}
}
} //Remove dead Nodes out of write loop to avoid trashing loop index
for(i=0;i<cleanup.length;i+=1) {
clientList.splice(clientList.indexOf(cleanup[i]), 1)
}
}
TCP API 中还提供一个 error 事件,用于捕捉客户端的异常:
client.on('error', function(e) {
console.log(e);
});
Node 网络编程的 API 还丰富,此次仅仅是个入门,更多的内容请接着看,关于浏览器 Socket 应用。
Socket.IO
前面说到,浏览器虽然也属于客户端的一种,但仅支持“单工”的 HTTP 通讯。有见及此,HTML5 新规范中推出了基于浏览器的 WebSocket,开发了底层的接口,允许我们能进行 更强大的操作,超越以往的 XHR。
如第一个例子那般,我们无须第三方框架就可以直接与 Node TCP 服务器 进行 Socket 通讯。
但我们又要认清一个事实,不是每个浏览器都可以顺利支持 WebSocket 的。于是 Socket.IO (http://socket.io)出现了,它提供了不支持 WebSocket 时候的降级支持,同时使得一些旧版本的浏览器也可以“全双工”地工作。优先使用的顺序如下:
经过封装,我们可以不探究客户端使用上述哪一种技术达致“全双工”;而我们编写代码时,亦无论考虑哪种放法,因为 Socket.IO 给我们的 API 只有一套。了解 Socket.IO 其用法就可以了。
先在浏览器部署 Socket.IO 的前端代码:
<!DOCTYPE html>
<html>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
// 当服务端发送一条消息到客户端,message 事件即被触发。我们把消息在控制台打印出来
socket.on('message', function(data){ console.log(data) })
</script>
</body>
</html>
服务端 Node 代码:
var http = require('http'),
io = require('socket.io'),
fs = require('fs');
// 虽然我们这里使用了同步的方法,那会阻塞 Node 的事件循环,但是这是合理的,因为 readFileSync() 在程序周期中只执行一次,而且更重要的是,同步方法能够避免异步方法所带来的“与 SocketIO 之间额外同步的问题”。当 HTML 文件读取完毕,而且服务器准备好之后,如此按照顺序去执行就能让客户端马上得到 HTML 内容。
var sockFile = fs.readFileSync('socket.html');
// Socket 服务器还是构建于 HTTP 服务器之上,因此先调用 http.createServer()
server = http.createServer();
server.on('request', function(req, res){
// 一般 HTTP 输出的格式
res.writeHead(200, {'content-type': 'text/html'});
res.end(sockFile);
});
server.listen(8080);
var socket = io.listen(server); // 交由 Socket.io 接管
// Socket.io 真正的连接事件
socket.on('connection', function(client){
console.log('Client connected');
client.send('Welcome client ' + client.sessionId); // 向客户端发送文本
});
当客户端连接时,服务端会同时出发两个事件:server.onRequest 和 Socket.onConnection。它们之间有什么区别呢?区别在于 Socket 的是持久性的。
多个 Socket 连接,先是客户端代码:
<!DOCTYPE html>
<html>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var upandrunning = io.connect('http://localhost:8080/upandrunning');
var weather = io.connect('http://localhost:8080/weather');
upandrunning.on('message', function(data){
document.write('<br /><br />Node: Up and Running Update<br />');
document.write(data);
});
weather.on('message', function(data){
document.write('<br /><br />Weather Update<br />');
document.write(data);
});
</script>
</body>
</html>
服务端代码:
var sockFile = fs.readFileSync('socket.html');
server = http.createServer();
server.on('request', function(req, res){
res.writeHead(200, {'content-type': 'text/html'});
res.end(sockFile);
});
server.listen(8080);
var socket = io.listen(server);
socket.of('/upandrunning')
.on('connection', function(client){
console.log('Client connected to Up and Running namespace.');
client.send("Welcome to 'Up and Running'");
});
socket.of('/weather')
.on('connection', function(client){
console.log('Client connected to Weather namespace.');
client.send("Welcome to 'Weather Updates'");
});
如上代码,我们可以划分多个命名空间,分别是 upandrunning 和 weather。
关于 Express 中使用 Soclet.io,可以参考《Node:Up and Ruuning》一书的 7.2.2 小节。
今晚时间的关系,涉及 Socket.io 许多方面还没有谈,容小弟我日后再了解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# nodejs
# socket通信
# socket.io
# socket
# nodejs结合Socket.IO实现的即时通讯功能详解
# Nodejs+Socket.io实现通讯实例代码
# 基于html5和nodejs相结合实现websocket即使通讯
# nodejs基于WS模块实现WebSocket聊天功能的方法
# 用nodejs搭建websocket服务器
# 浅析nodejs实现Websocket的数据接收与发送
# nodejs 使用nodejs-websocket模块实现点对点实时通讯
# 客户端
# 服务端
# 的是
# 这是
# 多个
# 网络编程
# 我们可以
# 移除
# 就可以
# 是一个
# 聊天室
# 全双工
# 我也
# 是个
# 是在
# 达致
# 还没有
# 都不
# 第一个
# 也就
相关文章:
如何通过免费商城建站系统源码自定义网站主题与功能?
江苏网站制作公司有哪些,江苏书法考级官方网站?
用v-html解决Vue.js渲染中html标签不被解析的问题
网站制作软件有哪些,制图软件有哪些?
西安专业网站制作公司有哪些,陕西省建行官方网站?
高性价比服务器租赁——企业级配置与24小时运维服务
网站制作公司,橙子建站是合法的吗?
建站之星3.0如何解决常见操作问题?
在线流程图制作网站手机版,谁能推荐几个好的CG原画资源网站么?
简历在线制作网站免费,免费下载个人简历的网站是哪些?
如何通过山东自助建站平台快速注册域名?
美食网站链接制作教程视频,哪个教做美食的网站比较专业点?
网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
Python lxml的etree和ElementTree有什么区别
高端智能建站公司优选:品牌定制与SEO优化一站式服务
如何选择服务器才能高效搭建专属网站?
手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?
如何用狗爹虚拟主机快速搭建网站?
香港网站服务器数量如何影响SEO优化效果?
常州自助建站费用包含哪些项目?
专业网站制作服务公司,有哪些网站可以免费发布招聘信息?
如何选择最佳自助建站系统?快速指南解析优劣
如何通过FTP空间快速搭建安全高效网站?
购物网站制作公司有哪些,哪个购物网站比较好?
广东企业建站网站优化与SEO营销核心策略指南
如何在Golang中引入测试模块_Golang测试包导入与使用实践
如何快速搭建响应式可视化网站?
详解jQuery中基本的动画方法
成都响应式网站开发,dw怎么把手机适应页面变成网页?
制作表格网站有哪些,线上表格怎么弄?
微网站制作教程,我微信里的网站怎么才能复制到浏览器里?
深圳网站制作培训,深圳哪些招聘网站比较好?
建站VPS能否同时实现高效与安全翻墙?
微网站制作教程,不会写代码,不会编程,怎么样建自己的网站?
如何用免费手机建站系统零基础打造专业网站?
免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?
如何在万网自助建站中设置域名及备案?
宁波自助建站系统如何快速打造专业企业网站?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
如何在VPS电脑上快速搭建网站?
如何确认建站备案号应放置的具体位置?
建站主机选择指南:服务器配置与SEO优化实战技巧
Swift中swift中的switch 语句
详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)
文字头像制作网站推荐软件,醒图能自动配文字吗?
建站主机SSH密钥生成步骤及常见问题解答?
整蛊网站制作软件,手机不停的收到各种网站的验证码短信,是手机病毒还是人为恶搞?有这种手机病毒吗?
制作网站外包平台,自动化接单网站有哪些?
建站之星多图banner生成与模板自定义指南
*请认真填写需求信息,我们会在24小时内与您取得联系。