golang实现CoAP协议客户端与服务端通信的插件库canopus的使用

Golang实现CoAP协议客户端与服务端通信的插件库Canopus的使用

Canopus是一个实现了RFC7252约束应用协议(CoAP)的客户端/服务器库。

简单示例

服务端代码

// 创建CoAP服务器
server := canopus.NewServer()

// 注册GET请求处理函数
server.Get("/hello", func(req canopus.Request) canopus.Response {
    // 创建确认消息
    msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
    msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())

    res := canopus.NewResponse(msg, nil)
    return res
})

// 监听5683端口
server.ListenAndServe(":5683")

客户端代码

// 连接到服务器
conn, err := canopus.Dial("localhost:5683")
if err != nil {
    panic(err.Error())
}

// 创建GET请求
req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID()).(*canopus.CoapRequest)
req.SetStringPayload("Hello, canopus")
req.SetRequestURI("/hello")

// 发送请求
resp, err := conn.Send(req)
if err != nil {
    panic(err.Error())
}

// 打印响应
fmt.Println("Got Response:" + resp.GetMessage().GetPayload().String())

观察/通知模式示例

服务端代码

server := canopus.NewServer()
server.Get("/watch/this", func(req canopus.Request) canopus.Response {
    msg := canopus.NewMessageOfType(canopus.MessageAcknowledgment, req.GetMessage().GetMessageId(), canopus.NewPlainTextPayload("Acknowledged"))
    res := canopus.NewResponse(msg, nil)
    return res
})

// 每3秒发送一次通知
ticker := time.NewTicker(3 * time.Second)
go func() {
    for {
        select {
        case <-ticker.C:
            changeVal := strconv.Itoa(rand.Int())
            fmt.Println("[SERVER << ] Change of value -->", changeVal)
            server.NotifyChange("/watch/this", changeVal, false)
        }
    }
}()

// 观察请求回调
server.OnObserve(func(resource string, msg canopus.Message) {
    fmt.Println("[SERVER << ] Observe Requested for " + resource)
})

server.ListenAndServe(":5683")

客户端代码

conn, err := canopus.Dial("localhost:5683")

// 观察资源
tok, err := conn.ObserveResource("/watch/this")
if err != nil {
    panic(err.Error())
}

// 创建观察通道
obsChannel := make(chan canopus.ObserveMessage)
done := make(chan bool)
go conn.Observe(obsChannel)

// 处理通知
notifyCount := 0
for {
    select {
    case obsMsg, _ := <-obsChannel:
        if notifyCount == 5 {
            fmt.Println("[CLIENT >> ] Canceling observe after 5 notifications..")
            go conn.CancelObserveResource("watch/this", tok)
            go conn.StopObserve(obsChannel)
            return
        } else {
            notifyCount++
            resource := obsMsg.GetResource()
            val := obsMsg.GetValue()
            fmt.Println("[CLIENT >> ] Got Change Notification for resource and value: ", notifyCount, resource, val)
        }
    }
}

使用PSK的dTLS示例

服务端代码

server := canopus.NewServer()

server.Get("/hello", func(req canopus.Request) canopus.Response {
    msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
    msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())
    res := canopus.NewResponse(msg, nil)
    return res
})

// 设置PSK处理函数
server.HandlePSK(func(id string) []byte {
    return []byte("secretPSK")
})

// 监听DTLS端口
server.ListenAndServeDTLS(":5684")

客户端代码

// 使用DTLS连接
conn, err := canopus.DialDTLS("localhost:5684", "canopus", "secretPSK")
if err != nil {
    panic(err.Error())
}

req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
req.SetStringPayload("Hello, canopus")
req.SetRequestURI("/hello")

resp, err := conn.Send(req)
if err != nil {
    panic(err.Error())
}

fmt.Println("Got Response:" + resp.GetMessage().GetPayload().String())

CoAP-CoAP代理示例

后端服务端代码

server := canopus.NewServer()

server.Get("/proxycall", func(req canopus.Request) canopus.Response {
    msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
    msg.SetStringPayload("Data from :5685 -- " + req.GetMessage().GetPayload().String())
    res := canopus.NewResponse(msg, nil)
    return res
})
server.ListenAndServe(":5685")

代理服务端代码

server := canopus.NewServer()
// 启用CoAP代理
server.ProxyOverCoap(true)

server.Get("/proxycall", func(req canopus.Request) canopus.Response {
    canopus.PrintMessage(req.GetMessage())
    msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
    msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())
    res := canopus.NewResponse(msg, nil)
    return res
})
server.ListenAndServe(":5683")

客户端代码

conn, err := canopus.Dial("localhost:5683")
if err != nil {
    panic(err.Error())
}

req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
// 设置代理URI
req.SetProxyURI("coap://localhost:5685/proxycall")

resp, err := conn.Send(req)
if err != nil {
    println("err", err)
}
canopus.PrintMessage(resp.GetMessage())

CoAP-HTTP代理示例

代理服务端代码

server := canopus.NewServer()
// 启用HTTP代理
server.ProxyOverHttp(true)

server.ListenAndServe(":5683")

客户端代码

conn, err := canopus.Dial("localhost:5683")
if err != nil {
    panic(err.Error())
}

req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
// 设置HTTP代理URI
req.SetProxyURI("https://httpbin.org/get")

resp, err := conn.Send(req)
if err != nil {
    println("err", err)
}
canopus.PrintMessage(resp.GetMessage())

更多关于golang实现CoAP协议客户端与服务端通信的插件库canopus的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现CoAP协议客户端与服务端通信的插件库canopus的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Canopus库实现CoAP协议通信

Canopus是一个轻量级的Go语言CoAP协议实现库,支持客户端和服务端功能。下面我将介绍如何使用Canopus实现基本的CoAP通信。

安装Canopus

首先需要安装Canopus库:

go get github.com/zubairhamed/canopus

CoAP服务端实现

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/zubairhamed/canopus"
)

func main() {
	// 创建CoAP服务端
	server := canopus.NewServer()
	
	// 设置默认路由,处理所有请求
	server.GetDefaultHandleFunc(func(req canopus.CoapRequest) canopus.CoapResponse {
		// 打印接收到的请求信息
		fmt.Printf("Received request: %+v\n", req.GetMessage())
		
		// 创建响应消息
		res := canopus.NewResponse(canopus.NewEmptyMessage(req.GetMessage().MessageId), nil)
		res.SetCode(canopus.Content)
		res.SetPayload(canopus.NewPlainTextPayload("Hello from CoAP Server!"))
		
		return res
	})
	
	// 添加特定资源路由
	server.Get("/time", func(req canopus.CoapRequest) canopus.CoapResponse {
		res := canopus.NewResponse(canopus.NewEmptyMessage(req.GetMessage().MessageId), nil)
		res.SetCode(canopus.Content)
		res.SetPayload(canopus.NewPlainTextPayload(time.Now().Format(time.RFC3339)))
		return res
	})
	
	// 启动服务端,监听5683端口(CoAP默认端口)
	err := server.ListenAndServe(":5683")
	if err != nil {
		log.Fatal(err)
	}
}

CoAP客户端实现

package main

import (
	"fmt"
	"log"

	"github.com/zubairhamed/canopus"
)

func main() {
	// 创建CoAP客户端
	client := canopus.NewClient()
	
	// 连接到服务端
	conn, err := client.Dial("localhost:5683")
	if err != nil {
		log.Fatal(err)
	}
	
	// 发送GET请求到默认资源
	req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get)
	req.SetRequestURI("/")
	
	resp, err := conn.Send(req)
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("Response from server: %s\n", resp.GetMessage().Payload.String())
	
	// 发送GET请求到/time资源
	req = canopus.NewRequest(canopus.MessageConfirmable, canopus.Get)
	req.SetRequestURI("/time")
	
	resp, err = conn.Send(req)
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("Current time from server: %s\n", resp.GetMessage().Payload.String())
}

高级功能

观察资源(Observe)

Canopus支持CoAP的观察功能,可以订阅资源的变化:

// 服务端代码 - 添加可观察资源
server.Get("/temp", func(req canopus.CoapRequest) canopus.CoapResponse {
	res := canopus.NewResponse(canopus.NewEmptyMessage(req.GetMessage().MessageId), nil)
	res.SetCode(canopus.Content)
	res.SetPayload(canopus.NewPlainTextPayload(fmt.Sprintf("%.1f°C", getTemperature())))
	
	// 标记为可观察资源
	res.SetObserve(1)
	return res
})

// 客户端代码 - 观察资源
req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get)
req.SetRequestURI("/temp")
req.SetObserve(0) // 启用观察

// 设置观察回调
conn.Observe(req, func(resp canopus.CoapResponse) {
	fmt.Printf("Temperature update: %s\n", resp.GetMessage().Payload.String())
})

资源发现

Canopus支持CoAP的资源发现功能:

// 客户端发现服务端资源
req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get)
req.SetRequestURI("/.well-known/core")

resp, err := conn.Send(req)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Discovered resources: %s\n", resp.GetMessage().Payload.String())

块传输(Block-wise Transfer)

对于大文件传输,Canopus支持块传输:

// 服务端代码 - 处理块传输
server.Get("/large", func(req canopus.CoapRequest) canopus.CoapResponse {
	largeData := make([]byte, 2048) // 2KB数据
	// 填充数据...
	
	res := canopus.NewResponse(canopus.NewEmptyMessage(req.GetMessage().MessageId), nil)
	res.SetCode(canopus.Content)
	res.SetPayload(canopus.NewBytesPayload(largeData))
	
	// 启用块传输
	res.SetBlock2(canopus.Block2{
		Num:  0,
		More: true,
		Size: 64, // 块大小
	})
	
	return res
})

注意事项

  1. Canopus默认使用UDP协议,CoAP也可以运行在TCP上(CoAP over TCP)
  2. 生产环境中应考虑添加安全层(CoAPs/DTLS)
  3. 对于资源受限设备,可以调整消息大小和重传参数
  4. Canopus还支持CoAP代理功能,可以构建CoAP-HTTP网关

Canopus提供了完整的CoAP协议实现,包括消息类型、选项和扩展功能,适合构建物联网设备和服务器之间的轻量级通信。

回到顶部