websocket早在几年前就已经很流行了,主要就是用于即时通讯这一方面应用,可以是聊天,也可使是直播流传输等等。
今天,就来说说如何使用 create-react-app + socket.io 实现简单的即时聊天。
Demo地址
准备工作
想要实现即时通讯,还是需要有服务器的支持,这里我使用的是一个简单配置的服务器
还是去年腾讯搞活动买的,还不错,有机会你们也可以去看看。阿里云腾讯云都会时不时的出一些活动,买一个服务器自己玩玩还是可以的。如果有活动,我可以在后面不断更新。
有了服务器以后就是敲代码了。
服务端实现
服务端我这里使用的是Nodejs作为后端语言,使用express+socket.io作为技术支持,具体的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| 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(__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('users', { userCount, userList }) console.log(`${user.username} 登出了`); })
socket.on("message", data => { if ( !data ) return messageList.push({ username: userList[socket.uid], message: data }) if( messageList.length > 30 ){ messageList.shift() } 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服务
1
| var io = require('socket.io')(http);
|
接下来就是连接服务端与客户端了。服务端如果想要连接到客户端的用户,那么就需要有方法一直监听到客户端用户访问网站的方法。socket.io中就为我们提供了一个 connection
方法。
1 2 3
| io.on("connection", socket => { })
|
connection
之后所有的操作都是写在这个 connection 的监听之中。
上面的 connection 中的代码需要注意的有几点,知道了这几点,那么socket.io对你就不是难事
io.on('监听事件名字', () => {})
方法是监听所有的用户。
connection
方法中的 socket
值得是当前用户,所以socket.on('监听事件名字', () => {})
是监听当前用户的操作。
io.emit('监听事件名字', 参数)
是发送消息给客户端,此时客户端会有一个监听的事件,监听事件名字服务端需要与客户端相同。
socket.broadcast.emit("监听事件名字", 参数)
这个方法可以发送消息给除了自已以外的其他的所有的用户。
客户端与服务端一样。
记住以上四点秘诀,玩转socket不是梦。
客户端实现
客户端使用create-react-app写的页面实现,下面贴出逻辑,就不放样式了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| 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)
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查看源码