HTTP keep-alive参考博文
socketio跨域 socketio跨域问题自己去了解

WebSocket

websocket可以实现客户端与服务端之间的数据实时通信。(长连接)

网络通信过程中的长连接与短连接

短连接: 客户端发起连接请求,请求建立连接,服务端接受请求,完成连接的创建,而后客户端通过该连接发送数据,服务端处理请求,返回响应,最后连接断开。这种通讯模式称为短连接。

特点:这种通讯模式将会及时的释放服务端资源,所以可以为更多的客户端提供服务。但是也有缺点:无状态。(每个请求都是独立的,无法保存客户端状态)

**长连接:**客户端发起连接请求,请求建立连接,服务端接受请求,完成连接的创建,而后客户端通过该连接发送数据,服务端处理请求,返回响应;服务端也可以主动的向客户端发送数据,客户端接收。这个过程中持续连接不断开。这种通讯模式称为长连接。

特点:支持客户端与服务端之间的实时通信。服务端可以随时随地向客户端发消息。缺点就是浪费服务端资源。

什么是websocket

websocket是一种在单TCP连接上进行的支持全双工通信(通信的过程中允许两个方向上同时完成数据传输)的一种协议。是一款长连接协议。

如何在网页中建立websocket连接?

服务端接收接收该连接?

客户端与服务端如何通过该websocket连接进行通信呢?

socket.io

https://socketio.bootcss.com/

socket.io是一个为浏览器与服务端之间提供实时的、双向的、基于事件通信的网络通信库。底层封装了websocket协议。提供了一些简单的API接口,方便的建立连接,收发消息,抹平了一些技术细节与浏览器兼容性问题。

建立连接的伪代码:

socket(套接字)就是一个javascript对象,对象的本质就是封装了属性与方法。socket中就封装了用于与对方通信时所需要的资源。

// 客户端 导入socket.io后
let socket = io('ws://localhost:3000/');// 服务端 安装socket.io后
let socketio = require('socket.io');
socketio.on('connection', (socket)=>{连接建立成功后执行
});

建立websocket连接

服务端代码:

  1. 新建项目(socketserver文件夹)

安装express。安装socket.io

cd socketserver
npm init   // 一路回车  生成package.json
npm install --save express   // 安装express
npm install --save socket.io   // 安装socket.io
  1. 基于socket.io提供的API,接收客户端的连接请求,建立websocket连接。
// index.js   服务端核心js文件
const express = require('express');
const server = express();
// 调用server.get()  server.post() 注册路由 接收请求// 配置websocket
// 获取express底层所使用的http模块
const http = require('http').createServer(server);
// websocket需要把通信相关路由注册到该底层http模块
const socketio = require('socket.io')(http);
socketio.on('connection', (socket)=>{console.log('有客户端进来了:'+socket.id)
});// 设置静态资源托管目录 public
server.use(express.static('public'));// 启动服务 不能再使用server.listen  而应该调用http.listen
// 因为socketio将通信相关路由注册到了http模块,而非express
// 所以http才可以接收到websocket请求,express则只用于处理http服务
http.listen(3000, function(){console.log('server is running...')
});

客户端代码:

为了避免跨域问题,设置静态资源托管目录public,把网页写在public中即可。

<script src="socket.io.js"></script>
<script>btnConn.addEventListener('click', ()=>{let socket = io('ws://localhost:3000/');console.log(socket);
});</script>

客户端与服务端之间进行通信

客户端发消息给服务端

客户端:

let socket = io('ws://localhost:3000/');
// 发消息    (emit 翻译为触发)
socket.emit('textmsg', '你瞅啥?!');

服务端:

socketio.on('connection', (socket)=>{// 监听客户端发过来的消息socket.on('textmsg', (data)=>{console.log(data)});
});

服务端发消息给客户端

服务端代码:

socket.on('textmsg', (data)=>{console.log(data)// 回复socket.emit("textmsg", '瞅你咋地~~');
});

客户端代码:

let socket = io('ws://localhost:3000/');
socket.on('textmsg', (data)=>{alert('xxxx');
});

服务端向所有客户端广播消息

socketio.on('connection', (socket)=>{socket.emit();   // 针对当前客户端发消息socketio.emit('textmsg', '兄弟们!');   // 向所有客户端都发消息
});

例子:文件夹目录为

客户端:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h2>websockt示例</h2><button id="btnConn">建立连接</button><button id="btnSend">向服务器端发消息</button><button id="btnSend3">向服务器端发消息:请服务器端准备群发</button><script src="socket.io.js"></script><script>let socket;// 建立连接btnConn.addEventListener("click", ()=>{// socket = io('ws//localhost:3000/');socket = io('ws://localhost:3000/');console.log(socket);// 因为接收信息是在建立完连接之后就监听,所以接收服务器的信息是在连接之后就开启接收socket.on("textmsg", (data)=>{window.alert(data);});});// 客户端主动发消息btnSend.addEventListener("click", ()=>{// textmsg 是代表在服务器端接收时要用该textmsg去接收,只跟此次发送和接收相关,// 即每次接收和发送的要匹配即可socket.emit("textmsg", "向服务器发送信息,单发");});btnSend3.addEventListener("click", ()=>{// textmsg 是代表在服务器端接收时要用该textmsg去接收,只跟此次发送和接收相关,// 即每次接收和发送的要匹配即可socket.emit("textmsg", "向服务器端发消息:请服务器端准备群发");});</script></body>
</html>

服务端:

//index.js 服务端核心js文件
const express = require('express');
const server = express();// 调用server.get() serve.post()注册路由,接收请求
// const socketio = require("socket.io");
// 建立服务端和socketio连接
// 获取express底层所使用的http模块,因为要通过express底层的http去发送请求,建立连接是用http,所以要获得http
const http = require('http').createServer(server);
// 要将express底层的http和socketio建立联系
const socketio = require('socket.io')(http);
// 监听连接事件,连接就触发回调函数
socketio.on("connection", (socket)=>{console.log(socket.id);// 1.服务器端主动发送消息// 1.1针对当前客户端发送消息// socket.emit("textmsg", "连接建立成功");// 1.2向所有客户端发送消息,通过socktio发送// 2.服务器端接收消息并发送消息// 通过socketio连接的是长连接,所以接收信息要在长链接接听中接收和处理socket.on('textmsg', (data)=>{//接收textmsg类型的消息,即可以理解为监听textmsg的信息,有该信息则进行回调函数调用console.log(data);// 回复客户端if(/向服务器发送信息,单发/.test(data)){socket.emit("textmsg", "回复客户端信息");}else{socketio.emit("textmsg", "给客户端们都群发信息");}});
});
// 如果之后要写接口,那么是用serve.get来接收,因为serve上绑定了socketio,所以可以直接用
// 页面有自动重连的功能,如果没有连接成功// 设置静态资源托管目录 public,即可以通过服务器地址直接访问该文件夹内的资源
server.use(express.static('public'));// 启动服务 不能再使用server.listen,而应该调用http.listen
// 因为sokectio将通信相关的路由注册到了http模块,而非express
// 所以http才可以接收到websockt请求,express则用于处理http服务
http.listen(3000, function(){console.log("serve is running");
})

实现群聊天室

需求如下:

  1. 在聊天界面中建立websocket连接。

  2. 当客户端点击发送按钮时,使用已经建立好的连接向服务端发送消息。服务端接收该消息后,将这个消息内容向所有已经连接的客户端再发一遍即可。

  3. 每个客户端需要监听服务端发回来的消息,控制台打印。

  4. 消息上屏。把接收到的消息显示在聊天记录区。

  5. 优化业务细节。

  6. 实时更新聊天室的人数。

    1. 在服务端实时维护一个表达在线人数的变量。count
    2. 一旦有客户端连接,count++
    3. 一旦有客户端断开连接,count--
    4. 无论count是递增了还是递减了,只要count有变化,就需要给所有客户端发消息emit('count_updated', count)
    5. 客户端监听并接收该消息类型,更新页面中的在线人数即可。
  7. 实现登录业务。

    1. index.html点击登录时,需要获取昵称(文本框里输入)与头像(随机生成文件名)。带着这两个参数一起跳转到chart.html

      // window.location.href = "chart.html"
      location = "chart.html?name=xxx&avatar=xx.jpg"
      
    2. chart.html中获取nameavatar,更新用户信息。

    3. 发消息时,不能只发送内容,而是需要发送一个对象:

      {content:'xxxx', name:'xx', avatar:'xxx.jpg'}

    4. 服务端接收后将原封不动的把对象发给所有客户端。一旦客户端接收到返回回来的对象,需要解析对象的属性,上屏。

聊天室文件夹结构为:

群聊完成了,私聊该如何解决?

每当客户端与服务端建立了一个websocket连接,客户端将会得到一个socket对象,服务端也会得到一个socket对象。这些socket对象用于与对方进行数据通信。所以服务端保存了与每个客户端通信所需要的的socket对象。

所以如何实现私聊?

亮亮发消息时,不仅需要发送消息内容,还需要发送对方的ID(也可以是name,总之得传递对方的唯一标识符)。服务端接收到该消息后,需要通过ID(也可以是name)找到与对方建立起来的socket连接对象,直接调用socket.emit()方法发消息即可。
但是这里依然存在着不足,这里在用户退出之后,没有清除对应的用户socket,所以这里依然要去不断完善。

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>微信聊天室</title><link rel="stylesheet" href="styles/normalize.css"><link rel="stylesheet" href="styles/reset.css"><link rel="stylesheet" href="styles/chart.css"></head><body><div id="login-container"><div class="login-title">微信聊天室</div><div class="login-user-icon"><img src="images/login.png" alt=""></div><div><input type="text" id="username" class="login-item login-username" placeholder="请输入聊天昵称"></div><div><input type="button" id="login" class="login-item login-button" value="登录"></div></div><script>// 为登录按钮绑定事件,点击之后跳转到chart.html页面,并且要把用户名和头像带过去// 通过location.href带过去login.addEventListener("click", ()=>{// 拿到用户名let name = username.value;// 头像的随机值let avatar = Math.floor(Math.random()*100);// 这里是相对路径,所以直接替换最后一个斜杆的内容let url = `chart.html?name=${name}&navatar=${avatar}.jpg`;console.log(url);// window.location = location// location == location.hreflocation.href = url;}); </script></body>
</html>

chart.html

chart.html```cpp
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>微信聊天室</title><link rel="stylesheet" href="styles/normalize.css"><link rel="stylesheet" href="styles/reset.css"><link rel="stylesheet" href="styles/chart.css"></head><body><div id="chart-container"><div class="chart-user-list" id="chart-user-list"><div class="user-item"  id="userinfo"><!-- <img src="images/avatar/15.jpg" alt="">未知名 --></div></div><div class="chart-main-area"><div class="chart-main-title"><h1>微信聊天室(<span id="userNumber"></span>)-<span id="currentUser"></span></h1></div><div class="chart-list" id="chart-list"><div class="user-logined" id="user-logined"><span id="logined-user"></span>上线了</div><!-- <div class="chart-item"><div class="user-face"><img src="images/avatar/11.jpg" alt=""></div><div class="user-message">111</div></div> --></div><div class="chart-form"><div><textarea class="chart-form-message" id="message" onkeydown="sendto(event.keyCode)"></textarea></div><div><input type="button" id="send" class="chart-form-send" value="发表"></div></div></div></div><script src="scripts/socket.io.js"></script><script>let str = window.location.search;if(!str){//如果没有参数,则不能跳转到chart页面location = "index.html";}// 这里要接收index传过来的参数,并且用于更新界面// 解析请求资源路径,获取name与avatorlet name = str.split("&")[0].split("=")[1];let avatar = str.split("&")[1].split("=")[1];name = decodeURI(name);// 更新页面中的头像与昵称:下面要注意头像的随机不是每个头像都有,因为文件夹内不连续userinfo.innerHTML = `<img src="images/avatar/${avatar}" alt="">${name}`;// 如果客户端和服务端的socket版本不一样。一个新旧,则会导致俩者无法正常交涉,会断开再连接let socket = io('ws://localhost:3000/');console.log(socket);// 登录并将用户名发送到服务端,让客户端根据名字将每个用户的socket保存起来socket.emit("login", name);// 更新群聊人数// 连接建立成功后,直接开始监听服务端发过来的count_updated消息socket.on("count_updated", (data)=>{// 把data更新到span中即可userNumber.innerHTML = data;});// 服务端上线,则界面通知socket.on("person", (data)=>{var person = document.getElementById("logined-user");person.innerHTML = data;// 过了一段时间之后,让通知消失var notice = document.getElementById("user-logined");setTimeout(()=>{notice.style.display = "none";}, 2000);});//版本一: 点击按钮发消息。头像是固定的// send.addEventListener("click", function(){//     // 获取textarea中输入的文本//     let msg = document.getElementById("message").value;//     // 发送给客户端消息//     if(msg.trim() && msg.length<30){//符合发送信息的要求,才可以发送给服务器//         // string.trim()是去除字符串左右俩端的字符串//         socket.emit("textmsg", msg);//         // 发送完毕之后让消息清空//         document.getElementById("message").value = "";//     }// });// 版本一:监听发送的消息// 连接建立成功后就直接开始监听服务端发过来的消息// socket.on("textmsg", (data)=>{//     console.log(data);//     // 将收到的消息添加到显示屏上//     // 构造一个聊天记录列表div,追加到聊天记录列表//     let div = document.createElement('div');//     div.className = 'chart-item';//     div.innerHTML = `<div class="user-face">//                         <img src="data:images/avatar/11.jpg" alt="">//                      </div>//                     <div class="user-message">${data}</div>`;//     // 把div追加到chart-list子元素的末尾位置//     let list = document.getElementById("chart-list");//     list.appendChild(div);//     // 将list元素的滚动条始终定位在最底部//     list.scrollTop = list.scrollHeight;// });//版本二: 点击按钮发消息。头像是变化的// send.addEventListener("click", function(){//     // 获取textarea中输入的文本//     let msg = document.getElementById("message").value;//     // 发送给客户端消息//     if(msg.trim() && msg.length<30){//符合发送信息的要求,才可以发送给服务器//         // string.trim()是去除字符串左右俩端的字符串//         // 这里将用户的发送内容和头像发送过服务端//         let allmsg = {content: msg, name: name, avatar: avatar};//         socket.emit("textmsg", allmsg);//         // 发送完毕之后让消息清空//         document.getElementById("message").value = "";//     }// });// 版本二(动态头像):监听发送的消息// 连接建立成功后就直接开始监听服务端发过来的消息socket.on("textmsg", (data)=>{console.log(data);// 将收到的消息添加到显示屏上// 构造一个聊天记录列表div,追加到聊天记录列表let div = document.createElement('div');div.className = 'chart-item';div.innerHTML = `<div class="user-face"><img src="images/avatar/${data.avatar}" alt=""></div><p style="font-size: 15px">${data.name}</p><div class="user-message">${data.content}</div>`;// 把div追加到chart-list子元素的末尾位置let list = document.getElementById("chart-list");list.appendChild(div);// 将list元素的滚动条始终定位在最底部list.scrollTop = list.scrollHeight;});// 封装发送信息的函数function sendmsg(){// 获取textarea中输入的文本let msg = document.getElementById("message").value;// 发送给客户端消息if(msg.trim() && msg.length<30){//符合发送信息的要求,才可以发送给服务器// string.trim()是去除字符串左右俩端的字符串// 这里将用户的发送内容和头像发送过服务端                 这里先写死私发给亮亮let allmsg = {content: msg, name: name, avatar: avatar, to:"亮亮"};socket.emit("textmsg", allmsg);// 发送完毕之后让消息清空document.getElementById("message").value = "";}}//版本三: 点击按钮发消息。头像是变化的,且回车会触发发送事件send.addEventListener("click", function(){// 点击按钮发送信息sendmsg();});// 回车触发的事件函数function sendto(key){if(key == 13){//回车sendmsg();} }</script></body>
</html>

app.js

const express = require('express');
const server = express();// 取出serve里的http底层
const http = require('http').createServer(server);
// serve和io建立联系
const socketio = require('socket.io')(http);// 用于保存实时在线人数
let count = 0;
// 保存用户们的{名字:socket}
let clients = {};socketio.on("connection", (socket)=>{console.log(`客户端${socket.id}访问`);// 有人连接服务器,就更新在线人数,把最新的count值发送给所有客户端count++;socketio.emit('count_updated', count);// 登录消息,通知上线// socket.emit('person', socket.id);// 捕获断开连接事件,count--socket.on("disconnect", ()=>{//因为是事件count--;socketio.emit('count_updated', count);});// 因为是事件处理函数,所以不能保证放在外面一定会执行,所以要放到事件的回调函数中// socketio.emit('count_updated', count);// 监听客户端发过来的消息做不同的处理socket.on("textmsg", (data)=>{//监听textmsg类型的数据,把数据放到data中// 1.群聊:将收到的信息群发给每个用户// socketio.emit("textmsg", data);//向所有客户端发送接收的信息// 2.私聊:将收到的信息,发送给前端指定发送的用户,这里的指定用户是写死的clients[data.to].emit("textmsg", data);});// 这里在每个用户连接之后,根据用户名保存每个socket对象socket.on("login", (data)=>{// 保存每个用户clients[data] = socket;console.log(clients);// 登录成功,通知上线socket.emit("person", data);});
});// 何时建立好连接,当客户端加载完页面之后就建立连接
// 群里思路是每个人发送给服务端,服务端将每个人发送的信息都转发给全部客户端// 设置公共目录
server.use(express.static('public'));
// 监听
http.listen(3000, function(){console.log("serve is running");
})

style/chart.css

body{background-color: #fff;font:14px/1.5 'Microsoft Yahei';
}
::-webkit-scrollbar {width:12px;}/* 滚动槽 */::-webkit-scrollbar-track {-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);border-radius:10px;}/* 滚动条滑块 */::-webkit-scrollbar-thumb {border-radius:10px;background:rgba(0,0,0,0.1);-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);}::-webkit-scrollbar-thumb:window-inactive {background:rgba(255,0,0,0.4);}
#login-container{width:285px;min-height:400px;border-radius: 4px;;margin:50px auto 0 auto;background-color: #F5F5F5;border:1px solid #ccc;
}
#login-container .login-title{height: 40px;line-height: 40px;padding-left:10px;border-bottom:1px solid #ddd;
}
#login-container .login-user-icon{width:120px;height: 120px;margin: 50px auto;;
}
#login-container .login-item{display: block;margin:0 auto 10px auto;
}
#login-container .login-username{width:190px;height: 30px;line-height: 30px;padding:0 5px;text-align: center;
}
#login-container .login-button{width:204px;background-color:#1AAD19;border: none;line-height: 40px;color:#fff;
}
#chart-container::before,#chart-container::after{content: '.';display: block;height: 0;visibility: hidden;clear: both;
}
#chart-container{width:900px;height: 500px;margin: 50px auto;border:1px solid #ccc;
}
#chart-container .chart-user-list{float:left;width:250px;height: 500px;background-color: #EAE8E7;
}
#chart-container .chart-user-list .user-item{padding:10px;border-bottom:1px solid #cccc;
}
#chart-container .chart-user-list .user-item img{margin-right: 5px;width: 40px;height: 40px;border-radius: 5px;vertical-align: middle;
}
#chart-container .chart-main-area{float:left;width:650px;height: 500px;background-color: #F5F5F5;
}
#chart-container .chart-main-area .chart-main-title{margin-bottom: 10px;;height: 60px;border-bottom:1px solid #cccc;
}
#chart-container .chart-main-area .chart-main-title h1{margin-left:20px;line-height: 60px;font-size:18px;}
#chart-container .chart-list{position: relative;height: 295px;overflow-Y: auto; overflow-X:hidden;
}
#chart-container .chart-list  .user-logined{position: absolute;bottom: 10px;width: 250px;padding: 10px;text-align: center;background-color: #DADADA;color: #000;left:190px;transition:all 0.8s ease-in-out;
}
#chart-container .chart-list .chart-item::after,#chart-container .chart-list .chart-item::before{content: '.';display: block;height: 0;visibility: hidden;clear: both;
}
#chart-container .chart-list .chart-item{margin-bottom: 10px;
}
#chart-container .chart-list .chart-item .user-face{float:left;margin:0 15px;
}
#chart-container .chart-list .chart-item .user-face img{width:40px;height: 40px;border-radius: 5px;
}
#chart-container .chart-list .chart-item .user-message{position: relative;float:left;padding:10px;min-width: 100px;max-width: 520px;background: #fff;font-size: 12px;border-radius: 3px;
}
#chart-container .chart-list .chart-item .user-message::before{content: ' ';position: absolute;width:10px;height:10px;background: #fff;top:10px;left:-5px;z-index: 222;transform: rotate(45deg);}
#chart-container .chart-form{height: 134px;background: #fff;
}
#chart-container .chart-form .chart-form-message{width:630px;padding:5px 10px;height: 95px;line-height: 1.5;resize:none;border: none;
}#chart-container .chart-form .chart-form-send{float: right;width: 70px;height: 24px;margin-right: 10px;background-color: #F5F5F5;color: #606060;border: 1px solid #ccc;cursor: pointer;
}

style/normalize.css

/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css *//* Document========================================================================== *//*** 1. Correct the line height in all browsers.* 2. Prevent adjustments of font size after orientation changes in iOS.*/html {line-height: 1.15; /* 1 */-webkit-text-size-adjust: 100%; /* 2 */}/* Sections========================================================================== *//*** Remove the margin in all browsers.*/body {margin: 0;}/*** Render the `main` element consistently in IE.*/main {display: block;}/*** Correct the font size and margin on `h1` elements within `section` and* `article` contexts in Chrome, Firefox, and Safari.*/h1 {font-size: 2em;margin: 0.67em 0;}/* Grouping content========================================================================== *//*** 1. Add the correct box sizing in Firefox.* 2. Show the overflow in Edge and IE.*/hr {box-sizing: content-box; /* 1 */height: 0; /* 1 */overflow: visible; /* 2 */}/*** 1. Correct the inheritance and scaling of font size in all browsers.* 2. Correct the odd `em` font sizing in all browsers.*/pre {font-family: monospace, monospace; /* 1 */font-size: 1em; /* 2 */}/* Text-level semantics========================================================================== *//*** Remove the gray background on active links in IE 10.*/a {background-color: transparent;}/*** 1. Remove the bottom border in Chrome 57-* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.*/abbr[title] {border-bottom: none; /* 1 */text-decoration: underline; /* 2 */text-decoration: underline dotted; /* 2 */}/*** Add the correct font weight in Chrome, Edge, and Safari.*/b,strong {font-weight: bolder;}/*** 1. Correct the inheritance and scaling of font size in all browsers.* 2. Correct the odd `em` font sizing in all browsers.*/code,kbd,samp {font-family: monospace, monospace; /* 1 */font-size: 1em; /* 2 */}/*** Add the correct font size in all browsers.*/small {font-size: 80%;}/*** Prevent `sub` and `sup` elements from affecting the line height in* all browsers.*/sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}/* Embedded content========================================================================== *//*** Remove the border on images inside links in IE 10.*/img {border-style: none;}/* Forms========================================================================== *//*** 1. Change the font styles in all browsers.* 2. Remove the margin in Firefox and Safari.*/button,input,optgroup,select,textarea {font-family: inherit; /* 1 */font-size: 100%; /* 1 */line-height: 1.15; /* 1 */margin: 0; /* 2 */}/*** Show the overflow in IE.* 1. Show the overflow in Edge.*/button,input { /* 1 */overflow: visible;}/*** Remove the inheritance of text transform in Edge, Firefox, and IE.* 1. Remove the inheritance of text transform in Firefox.*/button,select { /* 1 */text-transform: none;}/*** Correct the inability to style clickable types in iOS and Safari.*/button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}/*** Remove the inner border and padding in Firefox.*/button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}/*** Restore the focus styles unset by the previous rule.*/button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}/*** Correct the padding in Firefox.*/fieldset {padding: 0.35em 0.75em 0.625em;}/*** 1. Correct the text wrapping in Edge and IE.* 2. Correct the color inheritance from `fieldset` elements in IE.* 3. Remove the padding so developers are not caught out when they zero out*    `fieldset` elements in all browsers.*/legend {box-sizing: border-box; /* 1 */color: inherit; /* 2 */display: table; /* 1 */max-width: 100%; /* 1 */padding: 0; /* 3 */white-space: normal; /* 1 */}/*** Add the correct vertical alignment in Chrome, Firefox, and Opera.*/progress {vertical-align: baseline;}/*** Remove the default vertical scrollbar in IE 10+.*/textarea {overflow: auto;}/*** 1. Add the correct box sizing in IE 10.* 2. Remove the padding in IE 10.*/[type="checkbox"],[type="radio"] {box-sizing: border-box; /* 1 */padding: 0; /* 2 */}/*** Correct the cursor style of increment and decrement buttons in Chrome.*/[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}/*** 1. Correct the odd appearance in Chrome and Safari.* 2. Correct the outline style in Safari.*/[type="search"] {-webkit-appearance: textfield; /* 1 */outline-offset: -2px; /* 2 */}/*** Remove the inner padding in Chrome and Safari on macOS.*/[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}/*** 1. Correct the inability to style clickable types in iOS and Safari.* 2. Change font properties to `inherit` in Safari.*/::-webkit-file-upload-button {-webkit-appearance: button; /* 1 */font: inherit; /* 2 */}/* Interactive========================================================================== *//** Add the correct display in Edge, IE 10+, and Firefox.*/details {display: block;}/** Add the correct display in all browsers.*/summary {display: list-item;}/* Misc========================================================================== *//*** Add the correct display in IE 10+.*/template {display: none;}/*** Add the correct display in IE 10.*/[hidden] {display: none;}

style/reset.css

/* http://meyerweb.com/eric/tools/css/reset/v2.0-modified | 20110126License: none (public domain)
*/html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {margin: 0;padding: 0;border: 0;font-size: 100%;font: inherit;vertical-align: baseline;
}/* make sure to set some focus styles for accessibility */
:focus {outline: 0;
}/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {display: block;
}body {line-height: 1;
}ol, ul {list-style: none;
}blockquote, q {quotes: none;
}blockquote:before, blockquote:after,
q:before, q:after {content: '';content: none;
}table {border-collapse: collapse;border-spacing: 0;
}input[type=search]::-webkit-search-cancel-button,
input[type=search]::-webkit-search-decoration,
input[type=search]::-webkit-search-results-button,
input[type=search]::-webkit-search-results-decoration {-webkit-appearance: none;-moz-appearance: none;
}input[type=search] {-webkit-appearance: none;-moz-appearance: none;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;
}textarea {overflow: auto;vertical-align: top;resize: vertical;
}/*** Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.*/audio,
canvas,
video {display: inline-block;*display: inline;*zoom: 1;max-width: 100%;
}/*** Prevent modern browsers from displaying `audio` without controls.* Remove excess height in iOS 5 devices.*/audio:not([controls]) {display: none;height: 0;
}/*** Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.* Known issue: no IE 6 support.*/[hidden] {display: none;
}/*** 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using*    `em` units.* 2. Prevent iOS text size adjust after orientation change, without disabling*    user zoom.*/html {font-size: 100%; /* 1 */-webkit-text-size-adjust: 100%; /* 2 */-ms-text-size-adjust: 100%; /* 2 */
}/*** Address `outline` inconsistency between Chrome and other browsers.*/a:focus {outline: thin dotted;
}/*** Improve readability when focused and also mouse hovered in all browsers.*/a:active,
a:hover {outline: 0;
}/*** 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.* 2. Improve image quality when scaled in IE 7.*/img {border: 0; /* 1 */-ms-interpolation-mode: bicubic; /* 2 */
}/*** Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.*/figure {margin: 0;
}/*** Correct margin displayed oddly in IE 6/7.*/form {margin: 0;
}/*** Define consistent border, margin, and padding.*/fieldset {border: 1px solid #c0c0c0;margin: 0 2px;padding: 0.35em 0.625em 0.75em;
}/*** 1. Correct color not being inherited in IE 6/7/8/9.* 2. Correct text not wrapping in Firefox 3.* 3. Correct alignment displayed oddly in IE 6/7.*/legend {border: 0; /* 1 */padding: 0;white-space: normal; /* 2 */*margin-left: -7px; /* 3 */
}/*** 1. Correct font size not being inherited in all browsers.* 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,*    and Chrome.* 3. Improve appearance and consistency in all browsers.*/button,
input,
select,
textarea {font-size: 100%; /* 1 */margin: 0; /* 2 */vertical-align: baseline; /* 3 */*vertical-align: middle; /* 3 */
}/*** Address Firefox 3+ setting `line-height` on `input` using `!important` in* the UA stylesheet.*/button,
input {line-height: normal;
}/*** Address inconsistent `text-transform` inheritance for `button` and `select`.* All other form control elements do not inherit `text-transform` values.* Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.* Correct `select` style inheritance in Firefox 4+ and Opera.*/button,
select {text-transform: none;
}/*** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`*    and `video` controls.* 2. Correct inability to style clickable `input` types in iOS.* 3. Improve usability and consistency of cursor style between image-type*    `input` and others.* 4. Remove inner spacing in IE 7 without affecting normal text inputs.*    Known issue: inner spacing remains in IE 6.*/button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {-webkit-appearance: button; /* 2 */cursor: pointer; /* 3 */*overflow: visible;  /* 4 */
}/*** Re-set default cursor for disabled elements.*/button[disabled],
html input[disabled] {cursor: default;
}/*** 1. Address box sizing set to content-box in IE 8/9.* 2. Remove excess padding in IE 8/9.* 3. Remove excess padding in IE 7.*    Known issue: excess padding remains in IE 6.*/input[type="checkbox"],
input[type="radio"] {box-sizing: border-box; /* 1 */padding: 0; /* 2 */*height: 13px; /* 3 */*width: 13px; /* 3 */
}/*** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome*    (include `-moz` to future-proof).*/input[type="search"] {-webkit-appearance: textfield; /* 1 */-moz-box-sizing: content-box;-webkit-box-sizing: content-box; /* 2 */box-sizing: content-box;
}/*** Remove inner padding and search cancel button in Safari 5 and Chrome* on OS X.*/input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {-webkit-appearance: none;
}/*** Remove inner padding and border in Firefox 3+.*/button::-moz-focus-inner,
input::-moz-focus-inner {border: 0;padding: 0;
}/*** 1. Remove default vertical scrollbar in IE 6/7/8/9.* 2. Improve readability and alignment in all browsers.*/textarea {overflow: auto; /* 1 */vertical-align: top; /* 2 */
}/*** Remove most spacing between table cells.*/table {border-collapse: collapse;border-spacing: 0;
}html,
button,
input,
select,
textarea {color: #222;
}::-moz-selection {background: #b3d4fc;text-shadow: none;
}::selection {background: #b3d4fc;text-shadow: none;
}img {vertical-align: middle;
}fieldset {border: 0;margin: 0;padding: 0;
}textarea {resize: vertical;
}.chromeframe {margin: 0.2em 0;background: #ccc;color: #000;padding: 0.2em 0;
}

图片文件夹里面的图片为多张命名为数字的图片,0-99命名,其中有些缺少了。

websocket以及聊天室的实现相关推荐

  1. 基于WebSocket实现聊天室(Node)

    基于WebSocket实现聊天室(Node) WebSocket是基于TCP的长连接通信协议,服务端可以主动向前端传递数据,相比比AJAX轮询服务器,WebSocket采用监听的方式,减轻了服务器压力 ...

  2. java开发websocket聊天室_java实现基于websocket的聊天室

    [实例简介] java实现基于websocket的聊天室 [实例截图] [核心代码] chatMavenWebapp └── chat Maven Webapp ├── pom.xml ├── src ...

  3. 基于django channel 实现websocket的聊天室

    websocket ​ 网易聊天室? ​ web微信? ​ 直播? 假如你工作以后,你的老板让你来开发一个内部的微信程序,你需要怎么办?我们先来分析一下里面的技术难点 消息的实时性? 实现群聊 现在有 ...

  4. 视频教程-基于Java的WebSocket的聊天室-Java

    基于Java的WebSocket的聊天室 多年 Java 企业级应用开发工作经验,曾参与中国人寿.华夏人寿.泰康人寿.信达财险等保险行业内部业务管理系统以及线上在线产品的开发:参与中国人民银行.清华大 ...

  5. SpringBoot + Vue 实现基于 WebSocket 的聊天室(单聊)

    前言 在前一篇文章SpringBoot 集成 STOMP 实现一对一聊天的两种方法中简单介绍了如何利用 STOMP 实现单聊,本文则将以一个比较完整的示例展示实际应用,不过本文并未使用 STOMP,而 ...

  6. Python用tornado的websocket开发聊天室

    Python用tornado的websocket开发聊天室 用tornado开发基于异步websocket聊天室-demo 目录结构 Python包 main.py app/views.py temp ...

  7. SSM(五)基于webSocket的聊天室

    SSM(五)基于webSocket的聊天室 前言 不知大家在平时的需求中有没有遇到需要实时处理信息的情况,如站内信,订阅,聊天之类的.在这之前我们通常想到的方法一般都是采用轮训的方式每隔一定的时间向服 ...

  8. WebSocket 网页聊天室的实现(服务器端:.net + windows服务,前端:Html5)

    websocket是HTML5中的比较有特色一块,它使得以往在客户端软件中常用的socket在web程序中也能轻松的使用,较大的提高了效率.废话不多说,直接进入题. 网页聊天室包括2个部分,后端服务器 ...

  9. python tornado websocket_python tornado websocket 多聊天室(返回消息给部分连接者)

    1 #-*-coding:utf-8-*- 2 __author__ = 'zhouwang' 3 importjson4 importtornado.web5 importtornado.webso ...

  10. websocket(二):SSM+websocket的聊天室

    在github上面找了一个看起来还不错的网页版聊天室,基于ssm加websocket实现的,特此分享一下,github地址放在文章末尾,大家可以自行下载跑起来玩玩,项目如何跑起来我写在readme里面 ...

最新文章

  1. Silverlight OA源代码(Silverlight4+SQLServer2005)
  2. 难死金庸的考题(高中难度)
  3. 【实验】不会部署VRRP?看完就会了
  4. 机器人学习--Gazebo学习--模型库和编辑模型
  5. sqlsugar 批量删除guid类型主键_一文上手SqlSugar 「C# 数据操作系列」
  6. python调用C语言函数(方法)的几种方法
  7. Android传感器编程入门
  8. QT中的QTableView+QTableWidget
  9. EfficientDet:COCO 51.0 mAP!谷歌大脑提出目标检测新标杆
  10. Oracle 9i 返回一个记录集的方法
  11. 经典排序算法(十二)--地精排序Gnome Sort
  12. 服务器网站中断,如何解决无法打开网页及服务器已断开连接的问题?
  13. 中国广电明年推进5G覆盖乡镇,用户:和中国移动相比信号有何优势?
  14. 头歌——c++单向链表
  15. Dos命令 netstat -ano 查看端口占用及关闭进程
  16. 原创整理!计算机常用【快捷键、缩写、英语单词】不定更
  17. python中的list和array的不同之处
  18. 撕开的黎明--孔庆东卷
  19. win系列服务器,windows服务器系列系统
  20. 客户体验的全景分析:从了解到行动

热门文章

  1. AutoMagic使用说明
  2. 安卓应用禁止分屏模式方法
  3. 活动预告+征集讲师和话题:iOS/Android DevCamp | CMDN CLUB移动开发者俱乐部清凉夏日嘉年华 | 7月27日 7月28日 | 北京...
  4. MySQL 之 基本语法
  5. python文件开头# coding=gbk的用途
  6. QQ将在下一版本允许注销账号 预计下周发布
  7. 云服务器怎么采购便宜?云服务器优惠 3 大准则
  8. 【操作系统】主存空间的分配和回收
  9. 通信软件基础B-重庆邮电大学-Java-编程实现一个简单的聊天程序-多线程编程实现
  10. 小米十周年雷军演讲全文:和这个伟大时代同行,是最大的荣幸