Socketio搭建一个聊天室

前言
本次实验所用编程语言为HTML以及javascriptJQurey语言和Socketio框架,所用编辑文本工具为VS code

注意事项
(1)前端编程注意HTML语言的灵活运用以及javascript语言的使用。
(2)所要使用图片自己上网寻找替换即可。
(3)由于涉及隐私问题,所以代码实现效果图没有全部放出来。
(4)本文章主要用于大家学习参考,博客中代码按照步骤来即可执行使用,但请不要商用。。
(5)本聊天室功能参照B站视频完成,视频网址如下:https://www.bilibili.com/video/BV14K411T7cd?from=search&seid=16452167357705157739

聊天室具体功能
1、完成点对点即时的文本消息聊天功能。
2、实现Web的表情的发送、接收和显示功能。
3、实现Web的图片的发送、接收和显示功能。
4、实现本地消息的存储,在离线的时候也能加载和查看历史消息。
5、实现本地截图工具的调用。
6、实现视频的传输。

聊天室具体实现步骤
1、将VS code安装好。
(步骤一:进入VS code官网下载VS code安装包。)

(步骤二:选好安装路径,安装步骤直接默认即可。)

2、安装node.js
(步骤一:进入node.js官网下载node.js安装包。注意点击图中红线所画,下载稳定版本。)

(步骤二:选好安装路径,安装步骤直接默认即可。)

3、打开VS code,创建一个文件夹,再在文件夹下创建一个文件命名为app.js

4、右击app.js,点击图中红线所划打开终端。

5、在终端中执行指令yarn add nodejs-websocket添加node_modules

(本步骤可能遇到的报错一:)

(问题原因:Windows没有安装yarn
(解决办法:在Windows上安装yarn
【步骤一:运用管理员身份打开Windws PowerShell

【步骤二:在Windws PowerShell按照如下图所示执行指令】

6、在文件app.js中写如下代码。 (注:app.js是服务器文件)

/* 启动聊天的服务端程序
*/
var app = require('express')()
var server = require('http').Server(app)
var io = require('socket.io')(server)
// 记录所有已经登录过的用户
const users = []server.listen(3000, () => {console.log('服务器启动成功了')
})// express处理静态资源
// 把public目录设置为静态资源目录
app.use(require('express').static('public'))app.get('/', function(req, res) {res.redirect('/index.html')
})io.on('connection', function(socket) {socket.on('login', data => {// 判断,如果data在users中存在,说明该用户已经登录了,不允许登录// 如果data在users中不存在,说明该用户没有登录,允许用户登录let user = users.find(item => item.username === data.username)if (user) {// 表示用户存在, 登录失败. 服务器需要给当前用户响应,告诉登录失败socket.emit('loginError', { msg: '登录失败' })// console.log('登录失败')} else {// 表示用户不存在, 登录成功users.push(data)// 告诉用户,登录成功socket.emit('loginSuccess', data)// console.log('登录成功')// 告诉所有的用户,有用户加入到了聊天室,广播消息// socket.emit: 告诉当前用户// io.emit : 广播事件io.emit('addUser', data)// 告诉所有的用户,目前聊天室中有多少人io.emit('userList', users)// 把登录成功的用户名和头像存储起来socket.username = data.usernamesocket.avatar = data.avatar}})// 用户断开连接的功能// 监听用户断开连接socket.on('disconnect', () => {// 把当前用户的信息从users中删除掉let idx = users.findIndex(item => item.username === socket.username)// 删除掉断开连接的这个人users.splice(idx, 1)// 1. 告诉所有人,有人离开了聊天室io.emit('delUser', {username: socket.username,avatar: socket.avatar})// 2. 告诉所有人,userList发生更新io.emit('userList', users)})// 监听聊天的消息socket.on('sendMessage', data => {console.log(data)// 广播给所有用户io.emit('receiveMessage', data)})// 接收图片信息socket.on('sendImage', data => {// 广播给所有用户console.log(data);io.emit('receiveImage', data)})// 接收视频信息socket.on('sendVideo',data=>{//广播给所有用户console.log(data)io.emit('receiveVideo', data)})})

7、在wechart文件夹下创建一个public文件夹,用来存放css文件和js文件和images文件以及配置文件和index.html文件。
(注:index.html文件中代码如下:)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta http-equiv="X-UA-Compatible" content="ie=edge" /><title>聊天室</title><link rel="stylesheet" href="lib/jquery-mCustomScrollbar/css/jquery.mCustomScrollbar.min.css"/><link rel="stylesheet" href="lib/jquery-emoji/css/jquery.emoji.css"/><link rel="stylesheet" href="css/index.css" /></head><body><div class="login_box" style="display: block;"><h3>用户登录</h3><p>用户名</p><input type="text" placeholder="请输入用户名" id="username" /><p>选择头像</p><ul class="avatar" id="login_avatar"><li class="now"><img src="data:images/avatar01.jpg" alt="" /></li><li><img src="data:images/avatar02.jpg" alt="" /></li><li><img src="data:images/avatar03.jpg" alt="" /></li><li><img src="data:images/avatar04.jpg" alt="" /></li><li><img src="data:images/avatar05.jpg" alt="" /></li><li><img src="data:images/avatar06.jpg" alt="" /></li><li><img src="data:images/avatar07.jpg" alt="" /></li><li><img src="data:images/avatar08.jpg" alt="" /></li><li><img src="data:images/avatar09.jpg" alt="" /></li><li><img src="data:images/avatar10.jpg" alt="" /></li></ul><button class="weui-btn" id="loginBtn">登录</button></div><div class="container" style="display: none;"><!-- 用户列表 --><div class="user-list"><div class="header"><div class="avatar"><img class="img avatar_url" src="data:images/avatar2.jpg" alt="" /></div><div class="info"><!--  --><h3 class="username">清流</h3></div></div><div class="title"><h3>用户列表</h3></div><ul></ul></div><!-- 聊天主窗口 --><div class="box"><!-- 聊天窗口头部 --><div class="box-hd"><h3>聊天室(<span id="userCount">99</span>)</h3></div><!-- 聊天窗口主体区域 --><div class="box-bd"><!--<div class="system"><p class="message_system"><span class="content">"往事随风"邀请你和"Boy"加入了群聊</span></p></div><div class="message-box"><div class="my message"><img class="avatar" src="data:images/avatar2.jpg" alt="" /><div class="content"><div class="bubble"><div class="bubble_cont">在干嘛</div></div></div></div></div><div class="message-box"><div class="other message"><img class="avatar" src="data:images/avatar02.jpg" alt="" /><div class="content"><div class="nickname">小美</div><div class="bubble"><div class="bubble_cont">吃饭</div></div></div></div></div>--></div><!-- 聊天窗口底部区域 --><div class="box-ft"><!-- 工具栏 --><div class="toolbar"><a href="javascript:;" title="表情" class="face"></a><a href="Go://调用截图" title="截屏" class="screen-cut"><!--<label for="screen-cut"></label><input type="file" style="display: none;" id="screen-cut"/>--></a><a href="javascript:;" title="图片" class="file"><label for="file"></label><input type="file" id="file" style="display: none;"></a><a href="javascript:;" title="视频" class="videos"><label for="videos"></label><input type="file" style="display: none;" id="videos"/><!--<input type="file" id="videos" style="display: none;"></input>--></a></div><!-- 内容输入区域 --><div class="content"><!-- div添加一个属性:contenteditable --><div class="text" id="content" contenteditable></div></div><!-- 发送按钮 --><div class="action"><span class="desc">按下Ctrl+Enter发送</span><a class="btn-send" id="btn-send" href="javascript:;">发送</a></div></div></div></div></div><!-- 引入socketio --><script src="/socket.io/socket.io.js"></script><script src="js/jquery-1.12.4.js"></script><script src="lib/jquery-mCustomScrollbar/script/jquery.mCustomScrollbar.min.js"></script><script src="lib/jquery-emoji/js/jquery.emoji.min.js"></script><script src="js/index.js"></script><!--<script src="js/jquery-1.4.1.min.js"></script>--></body>
</html>

(注:index.css文件中代码如下:)

* {margin: 0;padding: 0;list-style: none;
}
html,
body {height: 100%;
}body {background: url('../images/bg.jpg') no-repeat center center;background-size: cover;
}
.container {max-width: 1000px;min-width: 800px;height: 100%;margin: 0 auto;background-color: pink;
}/*用户列表*/
.user-list {width: 280px;height: 100%;float: left;position: relative;/*background-color:#2e3238;*/background-color: #a5aebd;
}/*聊天主窗口*/
.box {overflow: hidden;height: 100%;background-color: #eee;position: relative;
}/*聊天窗口头部*/
.box-hd {text-align: center;position: absolute;top: 0;left: 0;width: 100%;line-height: 30px;
}/*聊天窗口头部文字*/
.box-hd h3 {font-size: 18px;font-weight: 400;padding: 10px 0;margin: 0 20px;border-bottom: 1px solid #ccc;z-index: 999;box-sizing: border-box;
}.message-box {overflow: hidden;
}/*聊天窗口主体部分*/
.box-bd {position: absolute;width: 100%;bottom: 180px;top: 51px;overflow-y: auto;overflow-x: hidden;
}.system {overflow: hidden;
}
.message_system {text-align: center;margin: 10px auto;max-width: 50%;
}.message_system .content {display: inline-block;font-size: 12px;padding: 1px 18px;color: #b2b2b2;border-radius: 2px;
}.other {margin-bottom: 16px;float: left;width: 100%;padding-left: 20px;box-sizing: border-box;
}.my {margin-bottom: 16px;float: right;width: 100%;text-align: right;padding-right: 20px;box-sizing: border-box;
}.my.message .avatar {float: right;
}.message .content {overflow: hidden;
}.message .content .nickname {font-weight: 400;padding-left: 10px;font-size: 12px;height: 22px;line-height: 24px;color: #4f4f4f;width: 350px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;word-wrap: normal;
}.message .avatar {width: 40px;height: 40px;border-radius: 2px;float: left;cursor: pointer;
}.my.message .bubble {background-color: #b2e281;
}
.message .bubble {max-width: 500px;min-height: 1em;display: inline-block;vertical-align: top;position: relative;text-align: left;font-size: 14px;border-radius: 3px;margin: 0 10px;background-color: #fff;
}/*图片信息*/
.message .bubble img {display: inline-block;cursor: pointer;max-width: 350px;max-height: 240px;
}/*自己消息信息*/
.message .bubble video {display: inline-block;cursor: pointer;max-width: 350px;max-height: 240px;
}.other .bubble:before {position: absolute;top: 14px;left: -10px;border: 6px solid transparent;content: ' ';border-right-color: #fff;border-right-width: 4px;
}.my .bubble:before {position: absolute;top: 14px;right: -10px;border: 6px solid transparent;content: ' ';border-left-color: #b2e281;border-left-width: 4px;
}.bubble_cont {word-wrap: break-word;word-break: break-all;min-height: 25px;padding: 9px 13px;
}/*他人视频消息*/
.bubble_cont video {word-wrap: break-word;word-break: break-all;min-height: 25px;padding: 9px 13px;
}/*聊天窗口底部区域*/
.box-ft {border-top: 1px solid #ccc;position: absolute;height: 180px;bottom: 0;right: 0;left: 0;
}.box-ft .toolbar {height: 30px;padding: 5px 20px;
}.box-ft .toolbar .face {display: inline-block;vertical-align: middle;width: 30px;height: 30px;background: url('../images/wechat-sprit.png') no-repeat -404px -398px;
}.box-ft .toolbar .screen-cut {display: inline-block;vertical-align: middle;width: 30px;height: 30px;background: url('../images/wechat-sprit.png') no-repeat -30px -432px;
}/*聊天窗口底部截屏*/
.box-ft .toolbar .screen-cut label {opacity: 0;width: 100%;height: 100%;display: block;cursor: pointer;background: rgb(255, 255, 255);
}.box-ft .toolbar .file label {opacity: 0;width: 100%;height: 100%;display: block;cursor: pointer;background: rgb(255, 255, 255);
}.box-ft .toolbar .file {display: inline-block;vertical-align: middle;width: 30px;height: 30px;background: url('../images/wechat-sprit.png') no-repeat -120px -432px;
}.box-ft .toolbar .videos label {opacity: 0;width: 100%;height: 100%;display: block;cursor: pointer;background: rgb(255, 255, 255);
}/*视频按钮*/
.box-ft .toolbar .videos {display: inline-block;vertical-align: middle;width: 30px;height: 30px;background: url('../images/wechat-sprit.png') no-repeat -430px -398px;
}.box-ft .content {height: 90px;overflow-x: hidden;padding: 0px 20px;
}.box-ft .content .text {resize: none;border: none;outline: none;width: 100%;height: 84px;font-size: 16px;background-color: #eee;
}.box-ft .action {text-align: right;margin-top: 5px;padding-right: 20px;
}.box-ft .action .desc {color: #888;font-size: 12px;margin-left: 10px;margin-right: 7px;
}.btn-send {display: inline-block;border: 1px solid #c1c1c1;text-decoration: none;background-color: #fff;color: #222;border-radius: 4px;padding: 3px 30px;font-size: 14px;
}.btn-send:hover {background-color: #d8d8d8;
}.header {padding: 18px;position: relative;
}.header .avatar {display: table-cell;vertical-align: middle;word-wrap: break-word;word-break: break-all;white-space: nowrap;padding-right: 10.625px;
}.header .avatar .img {width: 40px;height: 40px;border-radius: 2px;display: block;cursor: pointer;
}.header .info {display: table-cell;vertical-align: middle;word-wrap: break-word;word-break: break-all;width: 2000px;
}.header .info h3 {display: inline-block;font-weight: 400;width: 156px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;word-wrap: normal;color: #fff;font-size: 18px;vertical-align: top;line-height: 31px;text-decoration: none;
}.title {padding: 13px 18px 11px;border-bottom: 1px solid #24272c;border-top: 1px solid #24272c;color: #fff;
}.title h3 {font-weight: 400;font-size: 18px;
}.user {overflow: hidden;padding: 12px 18px 11px;border-bottom: 1px solid #292c33;cursor: pointer;position: relative;
}.user .avatar {float: left;margin-right: 10px;position: relative;
}.user .avatar img {display: block;width: 40px;height: 40px;border-radius: 2px;
}.user .name {color: #fff;overflow: hidden;line-height: 36px;
}.login_box {position: absolute;top: 50%;left: 50%;width: 380px;height: 380px;transform: translate(-50%, -50%);border-radius: 4px;/*background-color: #fff;*/background-color: rgba(128, 128, 128, 0.801);box-shadow: #999 0 2px 10px;
}.login_box h3 {text-align: center;color: #ffffff;/*color: #333;*/font-size: 24px;font-weight: 400;line-height: 100px;
}.login_box input {width: 300px;height: 30px;line-height: 30px;margin: 0 auto;padding: 0;display: block;outline: none;margin-bottom: 5px;
}.weui-btn {position: relative;display: block;width: 300px;margin: 0 auto;box-sizing: border-box;font-size: 14px;text-align: center;text-decoration: none;color: #ffffff;line-height: 2.55555556;border-radius: 5px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);overflow: hidden;background-color:lightgray;/*background-color: #1aad19;*/border: none;cursor: pointer;margin-top: 5px;
}.login_box ul {overflow: hidden;width: 280px;margin: 0 auto;border: 1px solid rgba(128, 128, 128, 0.801);/*border: 1px solid #ccc;*/padding: 0 10px;
}.login_box li {float: left;width: 44px;height: 44px;border: 2px solid transparent;margin: 0 4px;cursor: pointer;
}.login_box li.now {/*border-color: #1aad19;*/border-color:honeydew;
}.login_box img {width: 40px;height: 40px;display: block;
}.login_box p {height: 30px;line-height: 30px;padding-left: 38px;color: #ffffff;
}::-webkit-scrollbar-track-piece {background-color: #f8f8f8;
}
::-webkit-scrollbar {width: 6px;height: 6px;border-radius: 3px;
}
::-webkit-scrollbar-thumb {background-color: #ccc;background-clip: padding-box;min-height: 28px;
}
::-webkit-scrollbar-thumb:hover {background-color: #666;
}

(注:index.js文件中代码如下:)

/* 聊天室的主要功能
*/
/* 1. 连接socketio服务
*/
var socket = io('http://localhost:3000')
var username, avatar
/* 2. 登录功能
*/
$('#login_avatar li').on('click', function() {$(this).addClass('now').siblings().removeClass('now')
})
// 点击按钮,登录
$('#loginBtn').on('click', function() {// 获取用户名var username = $('#username').val().trim()if (!username) {alert('请输入用户名')return}// 获取选择的头像var avatar = $('#login_avatar li.now img').attr('src')// 需要告诉socket io服务,登录socket.emit('login', {username: username,avatar: avatar})
})// 监听登录失败的请求
socket.on('loginError', data => {alert('用户名已经存在')
})
// 监听登录成功的请求
socket.on('loginSuccess', data => {// 需要显示聊天窗口// 隐藏登录窗口$('.login_box').fadeOut()$('.container').fadeIn()// 设置个人信息console.log(data)$('.avatar_url').attr('src', data.avatar)$('.user-list .username').text(data.username)username = data.usernameavatar = data.avatar
})// 监听添加用户的消息
socket.on('addUser', data => {// 添加一条系统消息$('.box-bd').append(`<div class="system"><p class="message_system"><span class="content">${data.username}加入了群聊</span></p></div>`)scrollIntoView()
})// 监听用户列表的消息
socket.on('userList', data => {// 把userList中的数据动态渲染到左侧菜单$('.user-list ul').html('')data.forEach(item => {$('.user-list ul').append(`<li class="user"><div class="avatar"><img src="${item.avatar}" alt="" /></div><div class="name">${item.username}</div></li>      `)})$('#userCount').text(data.length)
})// 监听用户离开的消息
socket.on('delUser', data => {// 添加一条系统消息$('.box-bd').append(`<div class="system"><p class="message_system"><span class="content">${data.username}离开了群聊</span></p></div>`)scrollIntoView()
})// 聊天功能
$('.btn-send').on('click', () => {// 获取到聊天的内容var content = $('#content').html()$('#content').html('')if (!content) return alert('请输入内容')// 发送给服务器socket.emit('sendMessage', {msg: content,username: username,avatar: avatar})
})// 监听聊天的消息
socket.on('receiveMessage', data => {console.log(data);// 把接收到的消息显示到聊天窗口中if (data.username === username) {// 自己的消息$('.box-bd').append(`<div class="message-box"><div class="my message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="bubble"><div class="bubble_cont">${data.msg}</div></div></div></div></div>`)} else {// 别人的消息$('.box-bd').append(`<div class="message-box"><div class="other message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="nickname">${data.username}</div><div class="bubble"><div class="bubble_cont">${data.msg}</div></div></div></div></div>`)}scrollIntoView()
})function scrollIntoView() {// 当前元素的底部滚动到可视区$('.box-bd').children(':last').get(0).scrollIntoView(false)
}//发送图片功能$('#file').on('change', function() {var file = this.files[0]console.log(this.files[0]);// 需要把这个文件发送到服务器, 借助于H5新增的fileReadervar fr = new FileReader()fr.readAsDataURL(file)console.log("fr = " + fr.result);fr.onload = function() {socket.emit('sendImage', {username: username,avatar: avatar,img: fr.result})}
})// 监听图片聊天信息
socket.on('receiveImage', data => {// 把接收到的消息显示到聊天窗口中if (data.username === username) {// 自己的消息$('.box-bd').append(`<div class="message-box"><div class="my message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="bubble"><div class="bubble_cont"><img src="${data.img}"></div></div></div></div></div>`)} else {// 别人的消息$('.box-bd').append(`<div class="message-box"><div class="other message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="nickname">${data.username}</div><div class="bubble"><div class="bubble_cont"><img src="${data.img}"></div></div></div></div></div>`)}// 等待图片加载完成,在滚动到底部$('.box-bd img:last').on('load', function() {scrollIntoView()})
})//建立一个可存取到该file的url
function getObjectURL(file) {var url = null;if (window.createObjectURL != undefined) { // basicurl = window.createObjectURL(file);} else if (window.URL != undefined) { // mozilla(firefox)url = window.URL.createObjectURL(file);} else if (window.webkitURL != undefined) { // webkit or chromeurl = window.webkitURL.createObjectURL(file);}return url;
}//传输视频消息
$("#videos").change(function () {var objUrl = getObjectURL(this.files[0]);console.log("1111111111");console.log("objUrl = " + objUrl);socket.emit('sendVideo', {username: username,avatar: avatar,src: objUrl})});/*
$("#screen-cut").change(function () {console.log("22222");location.href = '%windir%\system32\SnippingTool.exe';
});
*/// 监听视频聊天信息socket.on('receiveVideo', data => {// 把接收到的消息显示到聊天窗口中console.log(data.src);if (data.username === username) {// 自己的消息$('.box-bd').append(`<div class="message-box"><div class="my message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="bubble"><div class="bubble_cont"><video style="height:auto;" src="${data.src}" id="video0" controls="controls"></video></div></div></div></div></div>`)} else {// 别人的消息$('.box-bd').append(`<div class="message-box"><div class="other message"><img class="avatar" src="${data.avatar}" alt="" /><div class="content"><div class="nickname">${data.username}</div><div class="bubble"><div class="bubble_cont"><video style="height:auto;" src="${data.src}" id="video0" controls="controls"></video></div></div></div></div></div>`)}// 等待图片加载完成,在滚动到底部$('.box-bd src:last').on('load', function() {scrollIntoView()})
})// 初始化jquery-emoji插件
$('.face').on('click', function() {$('#content').emoji({// 设置触发表情的按钮button: '.face',showTab: false,animation: 'slide',position: 'topRight',icons: [{name: 'QQ表情',path: 'lib/jquery-emoji/img/qq/',maxNum: 91,excludeNums: [41, 45, 54],file: '.gif'}]})
})

8、在js文件夹中参照网址http://eshengsky.github.io/jQuery-emoji/添加文件,完成文件布置。

(注:最后创建文件夹结构如下)

聊天室功能实现效果如下
1、启动服务器
(步骤一:打开cmd,按照如图所示执行指令。注:cd指令的目的是要进入代码文件所在目录)

2、打开浏览器输入localhost:3000,打开聊天室,进入登陆界面,输入用户名,选择头像。

3、进入登录界面以后,进行文本消息发送。

4、表情包发送。

5、截图工具调用。

6、实现图片和视频传输。

2021-06-14 Socketio学习使用搭建一个聊天室相关推荐

  1. emqttd java 即时通讯_使用Emqttd搭建一个聊天室

    前言 由于项目需要,目前需要使用Emqttd搭建一个聊天室,自己写了个demo,特记录下来 代码 使用IDEA搭建一个Spring Boot工程 pom.xml文件,此处我只列出dependencie ...

  2. java netty聊天室_netty实现消息中心(二)基于netty搭建一个聊天室

    前言 上篇博文(netty实现消息中心(一)思路整理 )大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天. 此demo ...

  3. node+socket.io 实现一个聊天室

    我们只做简单的实现,不接入数据库,nodejs也不使用express和koa等框架 因此依赖只有两个: 1.socket.io 2.mime(用于获取静态资源时获取文件的mime类型) 安装命令: n ...

  4. WebRTC 教程五:WebRTC搭建视频聊天室

    这篇文章主要介绍了 WebRTC 聊天室的整体演示,以及 WebRTC 视频聊天的功能设计,代码逻辑以及整体演示. 目录 WebRTC 聊天室:总体演示 WebRTC 视频聊天: 设计 WebRTC ...

  5. java聊天室小程序论文_在Java项目中利用continue与break制作一个聊天室小程序

    在Java项目中利用continue与break制作一个聊天室小程序 发布时间:2020-12-08 16:03:27 来源:亿速云 阅读:98 作者:Leah 在Java项目中利用continue与 ...

  6. 使用Swoole服务搭建简易聊天室

    前言: 之前写过一篇关于swoole的安装搭建的文章.也测试了搭建TCP协议的服务.但是今天我要介绍的是WebSocket协议,WebSoket协议的出现,解决了http协议的很大的一个缺陷.那就是服 ...

  7. 抓住语音社交风口,1天快速搭建语音聊天室

    语音聊天室孵化 一起KTV.众人大合唱.语音开黑.狼人杀.剧本杀.多人配音.观影.语音电台.相亲联谊社交等,一般都是在语音聊天室中进行,那么语音聊天室产品如此火热的原因有哪些呢? 一对一社交适用于朋友 ...

  8. 撸一个聊天室(vue+koa2+websokect+mongodb)

    撸一个聊天室(vue+koa2+websokect+mongodb) 本篇博客主要介绍聊天室项目,作者学习vue和node时间较短,若有什么错误或建议,欢迎指出,谢谢~ 贴上源码链接 -> 源码 ...

  9. 《Android Studio开发实战》学习(二)- 聊天室

    <Android Studio开发实战>学习(二)- 聊天室 背景 聊天室布局文件的编写 聊天室代码文件的编写 运行结果 背景 在前一篇文章 1中实现了使用Android Studio开发 ...

最新文章

  1. IT人的理性、激情与爱情
  2. python无效数据怎么办_Python使用sqlite插入数据无效的原因
  3. SQLLite (三):sqlite3_get_table,sqlite3_free_table
  4. Effective Java之用enum代替int常量(三十)
  5. P2805-[NOI2009]植物大战僵尸【网络流,最大权闭合图】
  6. Postgres访问其他PostgresQL数据库的功能DBLINK
  7. python字符编码正确的是_python字符编码
  8. jquery插件:图片截取工具jquery.imagecropper.js
  9. 字节跳动算法工程师总结:java自学路线及推荐书籍
  10. CSP学习之ASN.1编码(一)
  11. python监控网页变化教程_Python实时监控网站浏览记录实现过程详解
  12. Windows PE探秘
  13. java的serialization_Java序列化(Serialization) 机制
  14. asp.net 面试题目
  15. “赋能”企业,数加服装ERP智助企业乘风破浪
  16. 黑苹果简单的手动开启显示器HiDPI教程
  17. 2017.2.10考试总结2017冬令营
  18. android开发-验证邮箱输入是否合法
  19. Python herhan学习 day1
  20. 异常处理基于注解ExceptionHandler

热门文章

  1. .输入一行字符串,含有数字和非数字字符以及空格等,如: df23adfd56 2343?23dgjop535 如果将其中所有连续出现的数字视为一个整数,要求统计在该字符串中共有多少个整数,并将这些数依
  2. Spring Boot入门(08):整合Mybatis访问MySQL实现增删改查 | 超级详细,建议收藏
  3. matlab日期转儒略历,matlab儒略日转为日期
  4. arcgis中mxd批量导图(tif,png,jpg,pdf)
  5. PHP内核学习(一)SAPI
  6. 平板电脑如何刷linux,手把手教你六步刷系统
  7. 锐龙R3 4300U和i5-9300H 哪个好
  8. DDD理论学习系列(7)-- 值对象
  9. 四柱笔记(一):基本阴阳理论
  10. 一段经典模拟退火算法代码