socket.io简单介绍

在Html5中存在着这种一个新特性。引入了websocket,关于websocket的内部实现原理能够看这篇文章。这篇文章讲述了websocket无到有,依据协议,分析数据帧的头,进行构建websocket。尽管代码短。但能够非常好地体现websocket的原理。

http://blog.csdn.net/newpidian/article/details/50850670

,这个特性提供了浏览器端和server端的基于TCP连接的双向通道。

可是并非全部的浏览器都支持websocket特性。故为了磨平浏览器间的差异,为开发人员提供统一的接口,引入了socket.io模块。在不支持websoket的浏览器中,socket.io能够降级为其它的通信方式,比方有AJAX long polling 。JSONP Polling等。

模块安装

新建一个package.json文件,在文件里写入例如以下内容:

{
"name": "socketiochatroom",
"version": "0.0.1",
"dependencies": {
"socket.io": "*",
"express":"*"
}
}
npm install 

执行完这句,node将会从npm处下载socket.io和express模块。

    -

server端的实现

在文件夹中增加index.js文件,并在文件里写入例如以下内容:

/**
* Created by bamboo on 2016/3/31.
*/ var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function (req, res) {
"use strict";
res.end("<h1>socket server</h1>")
}); /*在线人员*/
var onLineUsers = {};
/* 在线人数*/
var onLineCounts = 0; /*io监听到存在链接。此时回调一个socket进行socket监听*/
io.on('connection', function (socket) {
console.log('a user connected');
/*监听新用户增加*/
socket.on('login', function (user) {
"use strict";
//暂存socket.name 为user.userId;在用户退出时候将会用到
socket.name = user.userId;
/*不存在则增加 */
if (!onLineUsers.hasOwnProperty(user.userId)) {
//不存在则增加
onLineUsers[user.userId] = user.userName;
onLineCounts++;
}
/*一个用户新增加,向全部client监听login的socket的实例发送响应,响应内容为一个对象*/
io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
console.log(user.userName, "增加了聊天室");//在server控制台中打印么么么用户增加到了聊天室
});
/*监听用户退出聊天室*/
socket.on('disconnect', function () {
"use strict";
if (onLineUsers.hasOwnProperty(socket.name)) {
var user = {userId: socket.name, userName: onLineUsers[socket.name]};
delete onLineUsers[socket.name];
onLineCounts--; /*向全部client广播该用户退出群聊*/
io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
console.log(user.userName, "退出群聊");
}
})
/*监听到用户发送了消息。就使用io广播信息。信息被全部client接收并显示。注意。假设client自己发送的也会接收到这个消息,故在client应当存在这的推断。是否收到的消息是自己发送的。故在emit时,应该将用户的id和信息封装成一个对象进行广播*/
socket.on('message', function (obj) {
"use strict";
/*监听到实用户发消息,将该消息广播给全部client*/
io.emit('message', obj);
console.log(obj.userName, "说了:", obj.content);
});
});
/*监听3000*/
http.listen(3000, function () {
"use strict";
console.log('listening 3000');
});

执行server端程序

node index.js

输出

listening 3000

此时在浏览器中打开localhost:3000会得到这种结果:

原因是在代码中仅仅对路由进行了例如以下设置

app.get('/', function (req, res) {
"use strict";
res.end("<h1>socket server</h1>")
});

server端主要是提供socketio服务,并没有设置路由。

client的实现

在client建立例如以下的文件夹和文件。当中json3.min.js能够从网上下载到。

client

- - - client.js

- - - index.html

- - - json3.min.js

- - - style.css

在index.html中

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no"/>
<meta name="format-detection" content="email=no"/>
<title>1301群聊</title>
<link rel="stylesheet" type="text/css" href="./style.css"/>
<script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script>
<script src="./json3.min.js"></script>
</head>
<body>
<div id="loginbox">
<div style="width: 260px;margin: 200px auto;">
输入你在群聊中的昵称
<br/>
<br/>
<input type="text" style="width:180px;" placeholder="请输入username" id="userName" name="userName"/>
<input type="button" style="width: 50px;" value="提交" onclick="CHAT.userNameSubmit();"/>
</div>
</div> <div id="chatbox" style="display: none;">
<div style="background: #3d3d3d;height: 28px;width: 100%;font-size: 12px">
<div style="line-height: 28px;color:#fff;">
<span style="text-align: left;margin-left: 10px;">1301群聊</span>
<span style="float: right;margin-right: 10px"><span id="showUserName"></span>|
<a href="javascript:;" onclick="CHAT.logout()" style="color: #fff;">退出</a></span>
</div>
</div>
<div id="doc">
<div id="chat">
<div id="message" class="message">
<div id="onLineCounts"
style="background: #EFEFF4; font-size: 12px;margin-top: 10px;margin-left: 10px;color: #666;">
</div>
</div>
<div class="input-box">
<div class="input">
<input type="text" maxlength="140" placeholder="输入聊天内容 " id="content" name="content" >
</div>
<div class="action">
<button type="button" id="mjr_send" onclick="CHAT.submit();">提交</button>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="./client.js"></script>
</body>
</html>

在client.js中

/**
* Created by bamboo on 2016/3/31.
*/
/*即时执行函数*/
(function () {
"use strict";
var d = document,
w = window,
dd = d.documentElement,
db = d.body,
dc = d.compatMode === "CSS1Compat",
dx = dc ? dd : db,
ec = encodeURIComponent,
p = parseInt;
w.CHAT = {
msgObj: d.getElementById("message"),
screenHeight: w.innerHeight ? w.innerHeight : dx.innerHeight,
userName: null,
userId: null,
socket: null,
/*滚动栏始终在最底部*/
scrollToBottom: function () {
w.scrollTo(0, this.msgObj.clientHeight);
},
/*此处仅为简单的刷新页面,当然能够做复杂点*/
logout: function () {
// this.socket.disconnect();
w.top.location.reload();
},
submit: function () {
var content = d.getElementById('content').value;
if (content != '') {
var obj = {
userId: this.userId,
userName: this.userName,
content: content
};
//如在server端代码所说,此对象即可想要发送的信息和发送人组合成为对象一起发送。
this.socket.emit('message', obj);
d.getElementById('content').value = '';
}
return false;
},
/**client依据时间和随机数生成ID,聊天username称能够反复*/
genUid: function () {
return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100);
},
/*更新系统信息
主要是在client显示当前在线人数。在线人列表等,当有新用户增加或者旧用户退出群聊的时候做出页面提示。*/
updateSysMsg: function (o, action) {
var onLineUsers = o.onLineUsers;
var onLineCounts = o.onLineCounts;
var user = o.user;
//更新在线人数
var userHtml = '';
var separator = '';
for (var key in onLineUsers) {
if (onLineUsers.hasOwnProperty(key)) {
userHtml += separator + onLineUsers[key];
separator = '、';
}
}
//插入在线人数和在线列表
d.getElementById('onLineCounts').innerHTML = '当前共同拥有' + onLineCounts + "在线列表: " + userHtml; //增加系统消息
var html = '';
html += '<div class="msg_system">';
html += user.userName;
html += (action === "login") ? "增加了群聊" : "退出了群聊";
html += '</div>';
var section = d.createElement('section');
section.className = 'system J-mjrlinkWrap J-cutMsg';
section.innerHTML = html;
this.msgObj.appendChild(section);
this.scrollToBottom();
}, /*用户提交username后,将loginbox设置为不显示,将chatbox设置为显示*/
userNameSubmit: function () {
var userName = d.getElementById('userName').value;
if (userName != '') {
d.getElementById('userName').value = '';
d.getElementById('loginbox').style.display = 'none';
d.getElementById('chatbox').style.display = 'block';
this.init(userName);//调用init方法
}
return false;
},
//用户初始化
init: function (userName) {
//随机数生成uid
this.userId = this.genUid();
this.userName = userName;
d.getElementById('showUserName').innerHTML = this.userName;//[newpidian]|[退出]
this.scrollToBottom();
//连接socketIOserver,newpidian的IP地址
this.socket = io.connect('192.168.3.155:3000');
//向server发送某用户已经登录了
this.socket.emit('login', {userId: this.userId, userName: this.userName});
//监听来自server的login,即在clientsocket.emit('login ')发送后,client就会收到来自server的
// io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
/*监听到实用户login了,更新信息*/
this.socket.on('login', function (o) {
//更新系统信息
CHAT.updateSysMsg(o, 'login');
});
/*监听到实用户logout了,更新信息*/
this.socket.on('logout', function (o) {
CHAT.updateSysMsg(o, 'logout');
});
//var obj = {
// userId: this.userId,
// userName: this.userName,
// content: content
//};
/*监听到实用户发送消息了*/
this.socket.on("message", function (obj) {
//推断消息是不是自己发送的
var isMe = (obj.userId === CHAT.userId);
var contentDiv = '<div>' + obj.content + '</div>';
var userNameDiv = '<span>' + obj.userName + '</span>';
var section = d.createElement('section');
if (isMe) {
section.className = 'user';
section.innerHTML = contentDiv + userNameDiv;
} else {
section.className = 'service';
section.innerHTML = userNameDiv + contentDiv;
}
CHAT.msgObj.appendChild(section);
CHAT.scrollToBottom();
});
}
}
/*控制键键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
BackSpace 8 Esc 27 Right Arrow 39 -_ 189
Tab 9 Spacebar 32 Dw Arrow 40 .> 190
Clear 12 Page Up 33 Insert 45 /? 191
Enter 13 Page Down 34 Delete 46 `~ 192
Shift 16 End 35 Num Lock 144 [{ 219
Control 17 Home 36 ;: 186 \| 220
Alt 18 Left Arrow 37 =+ 187 ]} 221
Cape Lock 20 Up Arrow 38 ,< 188 '" 222
* */
//通过“回车键”提交username
d.getElementById('userName').onkeydown = function (e) {
console.log(e);
e = e || event;
if (e.keyCode === 13) {
CHAT.userNameSubmit();
}
};
//通过“回车键”提交聊天内容
d.getElementById('content').onkeydown = function (e) {
e = e || event;
if (e.keyCode === 13) {
CHAT.submit();
}
};
})();

style.css

秘密

执行结果

server端已经执行。现将client也执行起来得到下图:

增加了new和pidian两个用户。并发送信息和进行退出,得到以下的结果:

利用socket.io实现多人聊天室(基于Nodejs)的更多相关文章

  1. vue + socket.io实现一个简易聊天室

    vue + vuex + elementUi + socket.io实现一个简易的在线聊天室,提高自己在对vue系列在项目中应用的深度.因为学会一个库或者框架容易,但要结合项目使用一个库或框架就不是那 ...

  2. 基于Node.js+socket.IO创建的Web聊天室

    这段时间进了一个新的项目组,项目是用Appcan来做一个跨平台的移动运维系统,其中前台和后台之间本来是打算用WebSocket来实现的,但写好了示例后发现android不支持WebSocket,大为受 ...

  3. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...

  4. html5的新通讯技术socket.io,实现一个聊天室

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Python基于Socket实现简易多人聊天室

    前言 套接字(Sockets)是双向通信信道的端点. 套接字可以在一个进程内,在同一机器上的进程之间,或者在不同主机的进程之间进行通信,主机可以是任何一台有连接互联网的机器. 套接字可以通过多种不同的 ...

  6. 利用socket.io构建一个聊天室

    利用socket.io来构建一个聊天室,输入自己的id和消息,所有的访问用户都可以看到,类似于群聊. socket.io 这里只用来做一个简单的聊天室,官网也有例子,很容易就做出来了.其实主要用的东西 ...

  7. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  8. 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室

    原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  9. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

随机推荐

  1. luogu P1592 互质

    题目描述 输入两个正整数n和k,求与n互质的第k个正整数. 输入输出格式 输入格式: 仅一行,为两个正整数n(≤10^6)和k(≤10^8). 输出格式: 一个正整数,表示与n互质的第k个正整数. 输 ...

  2. 记录一次eclipse的错误:“server tomcat v7.0 server at localhost was unable to start within 45 seconds”的问题解决思路

    如果配到上述问题,可以参考网上查找的方法,如下: http://stackoverflow.com/questions/6468520/server-tomcat-v6-0-server-at-loc ...

  3. asp.net获取请求的协议头是否启动了SSL(Https)

    方法: HttpContext.Current.Request.IsSecureConnection SLL:True HttpContext.Current.Request.Url.ToString ...

  4. mariadb设置utf8mb4

    1 . mysql真正的utf8是utf8mb4才是有效的utf8 a). mariaDB的设置方法 #vim /etc/my.conf [mysqld] character_set_server=u ...

  5. 80端口被屏蔽解决方法,80端口穿透之NAT端口映射技术

    介绍一种NAT端口映射技术应用,达到80端口穿透目的,解决80端口被屏蔽的问题,也是80端口被屏蔽解决方法中经常用到的. 80端口穿透类似80端口转发,因为80端口被屏蔽,在数据层面来说是不能直接访问 ...

  6. Java中的http相关的库:httpclient/httpcore/okhttp/http-request

    httpclient/httpcore是apache下面的项目:中文文档下载参考 5 官网:http://hc.apache.org/ 在线文档:http://hc.apache.org/httpco ...

  7. VS2010 MFC中 单独添加ODBC数据库记录集类(CRecordset)方法

    基于VS2010 MFC的项目是之前建好的,后来需要添加数据库. 方法分享于此. 1.  打开自己的项目,项目->添加类. 2. 选MFC ODBC使用者,点右下角的添加. 3. 点数据源. / ...

  8. 海量数据插入数据库效率对照測试 ---ADO.NET下SqlBulkCopy()对照LINQ 下InsertAllOnSubmit()

    摘要:使用.NET相关技术向数据库中插入海量数据是经常使用操作.本文对照ADO.NET和LINQ两种技术.分别使用SqlBulkCopy()和InsertAllOnSubmit()方法进行操作. 得出 ...

  9. AAuto如何设置定时器

    在设计视图中(一定要有个Form)点击左下角的功能组件   点击定时器即可切换到代码视图,并添加如下代码.其中我每隔一秒改变一下winform.static2.text的文本值      

  10. Webpack DLL

    参考自:https://www.jianshu.com/p/a5b3c2284bb6 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,我们希望能和自己的 ...