使用 Go 和 WebSockets 构建实时聊天服务器

使用 Go 和 WebSockets 构建实时聊天服务器

在本文中,您将使用 Websockets 在 Golang 中构建一个实时聊天应用程序。您还将使用 Docker 将应用程序容器化。

实时通信可能很难在您的应用程序中实现,但并非必须如此。Websockets 提供了一种简单而紧凑的方法,几乎​​可以在任何编程语言中使用。

在本文中,您将使用 Websockets 在 Golang 中构建一个实时聊天应用程序。您还将使用 Docker 将应用程序容器化。

构建实时聊天先决条件

  • Golang安装
  • 体验基本的 Go 语法
  • Docker 安装(可选)

设置我们的 Go 项目

让我们从创建项目所需的文件开始。这可以使用以下命令完成:

mkdir public
touch main.go Dockerfile public/index.html public/styles.css public/main.js

注意:mkdir命令创建一个新目录,touch 命令用于创建新文件。

基本 HTTP 服务器

并不是说您已经完成了文件夹结构的设置,您将继续使用gin包实现一个基本的 HTTP 服务器。

为此,您首先需要安装所需的依赖项:

go get github.com/gin-gonic/gin
go get gopkg.in/olahol/melody.v1

服务器将有一个 GET 端点来处理所有 Websocket 请求,并且还将提供一个用作前端的静态目录。

package main

import (
	static "github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.Use(static.Serve("/", static.LocalFile("./public", true)))

	r.GET("/ws", func(c *gin.Context) {
		m.HandleRequest(c.Writer, c.Request)
	})

	r.Run(":5000")
}

如您所见,服务器静态地为您之前创建的公共目录提供服务,并公开 /ws 的单个 GET 端点。

然后使用 run 命令启动服务器,该命令将端口作为参数。

实施 Websockets 服务器

现在您已经有了一个可以构建的基本 HTTP 服务器,让我们继续实现 Websockets 功能。为此,您将使用Melody 库,这是一个用于 Golang 编程语言的简约 Websockets 框架。

由于您只有一个 Websocket 事件,每当您发送聊天消息时都会触发该事件,因此您只需要将消息广播给其他客户端即可。

package main

import (
	static "github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
	"gopkg.in/olahol/melody.v1"
)

func main() {
	r := gin.Default()
	m := melody.New()

	r.Use(static.Serve("/", static.LocalFile("./public", true)))

	r.GET("/ws", func(c *gin.Context) {
		m.HandleRequest(c.Writer, c.Request)
	})

	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})

	r.Run(":5000")
}

HandleMessage() 函数用于接收发送到 Websockets GET 端点的所有消息。之后,您将消息广播给所有连接的客户端。

添加前端

下一步是在 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">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
    <title>Websockets Chat</title>
    <link rel="stylesheet" href="styles.css">
    <script type="text/javascript" src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
</head>
<body>
    <div class="container">
            <div class="row">
                <div class="col-md-6 offset-md-3 col-sm-12">
                    <h1 class="text-center">Socket IO Chat</h1>
                    <br>
                    <div id="status"></div>
                    <div id="chat">
                        <input type="text" name="username" id="username" class="form-control" placeholder="Enter name...">
                        <br>
                        <div class="card">
                            <div id="messages" class="card-block"></div>
                        </div>
                        <br>
                        <textarea id="textarea" name="inputMessage" class="form-control" placeholder="Enter message..."></textarea>
                        <br>
                        <button id="send" class="btn">Send</button>
                    </div>
                </div>
            </div>
    </div>
    <script type="text/javascript" src="main.js"></script>
</body>
</html>

您还在底部包含了 main.js 文件,这样您就可以为前端实现 websockets 客户端功能。

首先,您需要使用 document.querySelector() 函数从 Javascript DOM 获取前端布局的元素。

const input = document.querySelector('#textarea')
const messages = document.querySelector('#messages')
const username = document.querySelector('#username')
const send = document.querySelector('#send')

接下来,您连接到 Websockets 服务器并为onmessage事件创建侦听器。该事件将触发一个功能,将您收到的新消息插入到聊天中。

const url = "ws://" + window.location.host + "/ws";
const ws = new WebSocket(url);

ws.onmessage = function (msg) {
    insertMessage(JSON.parse(msg.data))
};

现在您可以接收传入的消息,是时候通过在发送按钮上放置一个onclick事件来发送消息了。

send.onclick = () => {
    const message = {
		username: username.value,
		content: input.value,
    }

    ws.send(JSON.stringify(message));
    input.value = "";
};

下一步是实现 insertMessage() 函数,该函数将使用 Javascript DOM 将接收到的消息插入文本区域。

/**
 * Insert a message into the UI
 * @param {Message that will be displayed in the UI} messageObj
 */
function insertMessage(messageObj) {
	// Create a div object which will hold the message
	const message = document.createElement('div')

	// Set the attribute of the message div
	message.setAttribute('class', 'chat-message')
	console.log("name: " +messageObj.username + " content: " + messageObj.content)
	message.textContent = `${messageObj.username}: ${messageObj.content}`

	// Append the message to our chat div
	messages.appendChild(message)

	// Insert the message as the first message of our chat
	messages.insertBefore(message, messages.firstChild)
}

所有这些都会产生以下 main.js 文件:

const input = document.querySelector('#textarea')
const messages = document.querySelector('#messages')
const username = document.querySelector('#username')
const send = document.querySelector('#send')

const url = "ws://" + window.location.host + "/ws";
const ws = new WebSocket(url);

ws.onmessage = function (msg) {
    insertMessage(JSON.parse(msg.data))
};

send.onclick = () => {
    const message = {
		username: username.value,
		content: input.value,
	}

    ws.send(JSON.stringify(message));
    input.value = "";
};

/**
 * Insert a message into the UI
 * @param {Message that will be displayed in the UI} messageObj
 */
function insertMessage(messageObj) {
	// Create a div object which will hold the message
	const message = document.createElement('div')

	// Set the attribute of the message div
	message.setAttribute('class', 'chat-message')
	console.log("name: " +messageObj.username + " content: " + messageObj.content)
	message.textContent = `${messageObj.username}: ${messageObj.content}`

	// Append the message to our chat div
	messages.appendChild(message)

	// Insert the message as the first message of our chat
	messages.insertBefore(message, messages.firstChild)
}

最后,您将向 styles.css 文件添加一些 css。

#messages{
    height:300px;
    overflow-y: scroll;
}

测试应用程序

太棒了,现在我们已经完成了应用程序,您可以使用以下命令运行它。

go run main.go

您现在可以在两个不同的浏览器选项卡中访问 localhost:5000 并开始相互聊天。

容器化应用程序

现在的最后一步是使用 Docker 将应用程序容器化。为此,我们可以使用一个简单的 Dockerfile 来构建和运行应用程序。

FROM golang:latest

# Set the Current Working Directory inside the container
WORKDIR /app

RUN GO111MODULE=on

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

COPY . . 

# Build the application
RUN go build -o main .

# Expose port 5000 to the outside world
EXPOSE 5000

# Command to run the executable
CMD ["./main"]

可以使用build命令构建图像。-t 标志用于为图像提供自定义标签。

docker build -t websocketschat .

您现在可以使用运行命令运行图像。-p 标志用于设置应向主机公开的端口。

docker run -p 5000:5000 websocketschat

整个项目和许多其他 Golang 项目都可以在我的 Github上找到。

结论

你一路走到最后!我希望本文能帮助您了解 Websockets 以及如何在 Golang 应用程序中使用它。

作者:Gabriel Tanner
原文链接:https://gabrieltanner.org/blog/realtime-chat-go-websockets/

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/im/14802.html

(0)

相关推荐

发表回复

登录后才能评论