在上一篇文章中,我们已经创建了一个代理,以升级一个传统的应用程序,发送原始的TCP套接字到一个HTTP服务器,而不改变原来的应用程序。
现在我们要做同样的事情,但不是发送HTTP请求,我们要连接到一个MQTT代理。可能尝试改变传统的应用程序来连接到MQTT代理是一个噩梦,但用这种方法是非常简单的。
这个想法是一样的。我们将发送我们的TCP套接字到localhost。然后我们要建立一个go客户端,读取TCP套接字,并将信息发送到MQTT代理。
我们将使用Mosquitto作为MQTT代理。我们可以用docker轻松地进行设置。
version: '2'
services:
mosquitto:
image: eclipse-mosquitto
hostname: mosquitto
container_name: mosquitto
build:
context: .docker/mosquitto
dockerfile: Dockerfile
expose:
- "1883"
- "9001"
ports:
- "1883:1883"
- "9001:9001"
我们也可以用mosquitto.conf和 users.txt设置我们的Mosquitto服务器的用户和密码。在这个例子中,我们要使用的凭证是:username:password
username:$6$6jOr4vVqaKxisTls$4KVYh8NBZdP+z4S/YbuoSHKlJ+5F1DxiE7XtWWXVHQ+7PlCI+b6LhqSbj8lL45HnGlo4D5t0AVFYrYGjb5lTxg==
我们的Go程序与http版本非常相似。
package main
import (
"bufio"
"encoding/json"
"flag"
mqtt "github.com/eclipse/paho.mqtt.golang"
"log"
"net"
"os"
"strings"
"time"
)
func main() {
port, closeConnection, topic, broker := parseFlags()
openSocket(*port, *closeConnection, *topic, *broker, onMessage)
}
func openSocket(port string, closeConnection bool, topic string, broker string, onMessage func(url string, topic string, buffer string)) {
PORT := "localhost:" + port
l, err := net.Listen("tcp4", PORT)
log.Printf("Serving %s\n", l.Addr().String())
if err != nil {
log.Fatalln(err)
}
defer l.Close()
for {
c, err := l.Accept()
if err != nil {
log.Fatalln(err)
}
go handleConnection(c, closeConnection, topic, broker, onMessage)
}
}
func createClientOptions(url string) *mqtt.ClientOptions {
opts := mqtt.NewClientOptions()
opts.AddBroker(url)
opts.SetUsername(os.Getenv("MQTT_USERNAME"))
opts.SetPassword(os.Getenv("MQTT_PASSWORD"))
return opts
}
func connect(url string) mqtt.Client {
opts := createClientOptions(url)
client := mqtt.NewClient(opts)
token := client.Connect()
for !token.WaitTimeout(3 * time.Second) {
}
if err := token.Error(); err != nil {
log.Fatal(err)
}
return client
}
func onMessage(url string, topic string, buffer string) {
client := connect(url)
client.Publish(topic, 0, false, buffer)
}
func parseFlags() (*string, *bool, *string, *string) {
port := flag.String("port", "7777", "port number")
closeConnection := flag.Bool("close", true, "Close connection")
topic := flag.String("topic", "topic", "mqtt topic")
broker := flag.String("broker", "tcp://localhost:1883", "mqtt topic")
flag.Parse()
return port, closeConnection, topic, broker
}
func handleConnection(c net.Conn, closeConnection bool, topic string, broker string, onMessage func(url string, topic string, buffer string)) {
log.Printf("Accepted connection from %s\n", c.RemoteAddr().String())
for {
ip, port, err := net.SplitHostPort(c.RemoteAddr().String())
netData, err := bufio.NewReader(c).ReadString('\n')
if err != nil {
log.Println(err)
}
message := map[string]interface{}{
"body": strings.TrimSpace(netData),
"ipFrom": ip,
"port": port,
}
log.Printf("sending to topic %s message:%s\n", topic, message)
bytesRepresentation, err := json.Marshal(message)
if err != nil {
log.Println(err)
} else {
onMessage(broker, topic, string(bytesRepresentation))
}
if closeConnection {
c.Close()
return
}
}
c.Close()
}
这就是全部。我们的传统应用程序现在可以毫无问题地讲MQTT了。
源代码可在我的github上找到