使用socket实现即时通讯聊天室
- 2019 年 11 月 28 日
- 笔记
websocket早在几年前就已经很流行了,主要就是用于即时通讯这一方面应用,可以是聊天,也可使是直播流传输等等。
今天,就来说说如何使用 create-react-app + socket.io 实现简单的即时聊天。
准备工作
想要实现即时通讯,还是需要有服务器的支持,这里我使用的是一个简单配置的服务器

还是去年腾讯搞活动买的,还不错,有机会你们也可以去看看。阿里云腾讯云都会时不时的出一些活动,买一个服务器自己玩玩还是可以的。如果有活动,我可以在后面不断更新。
有了服务器以后就是敲代码了。
服务端实现
服务端我这里使用的是Nodejs作为后端语言,使用express+socket.io作为技术支持,具体的代码如下
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服务
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写的页面实现,下面贴出逻辑,就不放样式了
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查看源码