websocket早在几年前就已经很流行了,主要就是用于即时通讯这一方面应用,可以是聊天,也可使是直播流传输等等。
今天,就来说说如何使用 create-react-app socket.io 实现简单的即时聊天。
Demo地址
准备工作
想要实现即时通讯,还是需要有服务器的支持,这里我使用的是一个简单配置的服务器
还是去年腾讯搞活动买的,还不错,有机会你们也可以去看看。阿里云腾讯云都会时不时的出一些活动,买一个服务器自己玩玩还是可以的。如果有活动,我可以在后面不断更新。
有了服务器以后就是敲代码了。
服务端实现
服务端我这里使用的是Nodejs作为后端语言,使用express socket.io作为技术支持,具体的代码如下
代码语言:javascript复制const express = require("express")
const app = express()
const http = require("http").createServer(app)
var io = require('socket.io')(http);
app.use(express.static(__dirname '/dist'))
app.get("/", (req, res) => {
res.header("Access-Control-Allow-Credentials", "true");
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
// res.send(`<h1>Hello World!!!</h1>`)
res.send(__dirname '/dist/index.html')
})
const userList = {};
let userCount = 0;
const messageList = []
io.on("connection", socket => {
socket.on("login", data => {
console.log(`${data.username} 登录`);
socket.uid = data.uid
userList[data.uid] = data.username
userCount
io.emit('users', {
userCount,
userList
})
// 发给自己
socket.emit("receive_message", messageList)
})
socket.on("disconnect", function() {
if( !socket.uid ) return
const user = {
uid: socket.uid,
username: userList[socket.uid]
}
delete userList[socket.uid]
userCount--
// 发送给所有用户 使用 io.emit
// 发送给自己 使用 socket.emit
io.emit('users', {
userCount,
userList
})
console.log(`${user.username} 登出了`);
})
socket.on("message", data => {
if ( !data ) return
// console.log(`发送信息 -- ${data}`);
messageList.push({
username: userList[socket.uid],
message: data
})
if( messageList.length > 30 ){
messageList.shift()
}
// 发送给除了自己以外的其他所有用户
// socket.broadcast.emit("receive_message", messageList)
io.emit("receive_message", messageList)
})
})
http.listen(2000, _ => {
console.log('This server is running: http://localhost:2000');
})
静态的文件是使用 create-react-app 开发的页面,build之后放到了服务器上面dist目录下面。
要使用socket.io,首先需要创建socket服务
代码语言:javascript复制var io = require('socket.io')(http);
接下来就是连接服务端与客户端了。服务端如果想要连接到客户端的用户,那么就需要有方法一直监听到客户端用户访问网站的方法。socket.io中就为我们提供了一个 connection
方法。
io.on("connection", socket => {
// do something
})
connection
之后所有的操作都是写在这个 connection 的监听之中。
上面的 connection 中的代码需要注意的有几点,知道了这几点,那么socket.io对你就不是难事
io.on('监听事件名字', () => {})
方法是监听所有的用户。connection
方法中的socket
值得是当前用户,所以socket.on('监听事件名字', () => {})
是监听当前用户的操作。io.emit('监听事件名字', 参数)
是发送消息给客户端,此时客户端会有一个监听的事件,监听事件名字服务端需要与客户端相同。socket.broadcast.emit("监听事件名字", 参数)
这个方法可以发送消息给除了自已以外的其他的所有的用户。
客户端与服务端一样。
记住以上四点秘诀,玩转socket不是梦。
客户端实现
客户端使用create-react-app写的页面实现,下面贴出逻辑,就不放样式了
代码语言:javascript复制import React, { Component } from 'react';
import './App.css';
import io from 'socket.io-client'
import { Input, Button, Avatar, message } from 'antd'
const socket = io('http://118.24.6.33:2000');
class App extends Component {
constructor(props){
super(props)
this.state = {
showLogin: true,
users: {
userCount: 0,
userList: {}
},
messageList: []
}
}
login = () => {
const username = this.refs.input.input.value.trim()
const { userList } = this.state.users
if( username.length ){
for (const k in userList) {
if( userList[k] === username ){
message.info("聊天室已经有这个用户了,请重新起一个名字")
return
}
}
this.uid = this.get_uid()
socket.emit("login", {
username,
uid: this.uid
})
this.setState({
showLogin: false
})
} else {
message.info("请输入一个用户名!!")
}
}
get_uid = _ => {
return `${new Date().getTime()}${Math.floor(Math.random() * 89999)}`
}
send = _ => {
this.message = this.refs.message.input.value
if (this.message.trim().length === 0) {
message.info("你还啥子都还没有输入就行发送了嘛")
return
}
const id = `${new Date().getTime()}${Math.floor(Math.random() * 9999)}`
const data = {
message: this.message.trim(),
uid: this.uid,
id
}
socket.emit('message', data)
// ant design 中清空输入的内容
this.refs.message.state.value = ''
setTimeout(_ => this.refs.messages.scrollBy(0, 999999), 100)
}
componentDidMount(){
socket.on("users", data => {
this.setState({users: data})
})
socket.on("receive_message", data => {
this.setState({messageList: data})
})
}
render(){
const { showLogin, users, messageList } = this.state
const { userCount, userList } = users
if (showLogin) {
return (
<div className="App">
<Input placeholder="输入一个名字撒" allowClear ref='input' onPressEnter={this.login}/>
<Button onClick={this.login} className="login">登录</Button>
</div>
);
} else {
return (
<div className="room">
<div className='inner'>
<header>欢迎来到踏浪聊天室,当前聊天室共{userCount}人</header>
<div className="content">
<ul className="user-list">
{
Object.entries(userList).map(v => {
return <li
className="user-list-item"
key={v[0]}
>
<Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
{v[1].substring(0, 2)}
</Avatar>
{v[1]}
</li>
})
}
</ul>
<ul className="message-list" ref="messages">
{
messageList.map(v => <li
key={v.message.id}
className={v.message.uid === this.uid ? "message-list-item me" : "message-list-item"}
>
{v.message.uid === this.uid && <span className="message-content">{v.message.message}</span>}
<Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
{v.username && v.username.substring(0, 2)}
</Avatar>
{v.message.uid !== this.uid && <span className="message-content">{v.message.message}</span>}
</li>)
}
</ul>
</div>
<footer>
<Input
placeholder="请输入消息"
ref='message'
onPressEnter={this.send}
/>
<Button className="send" onClick={this.send}>发送</Button>
</footer>
</div>
</div>
)
}
}
}
export default App
客户端可是使用的socket.io。不过使用的是专门为客户端提供的socket.io-client
。客户端首先需要连接到服务器,通过 const socket = io('http://118.24.6.33:2000');
就可以创建一个与服务端链接的 socket 请求。
接下来就是在 componentDidMount
中编写监听事件,同时 socket.on()
实现监听。
在事件中使用 socket.emit()
实现向后端发送消息。
整的逻辑的实现就是如此,摸清逻辑,后面的就不难了。
上面只是使用可socket.io的一些简单的API,关于更多的方法可以前往socket.io官网
最后,可以前往github查看源码