Example for block transfer with UDP CoAP
Hi,
Is there documentation or examples related to CoAP for block transfer for both client and server?
I searched throughout the examples and files and still did not find it. I would like to send a big chunk of payload around 1024 bytes from client to server. The simple example is the opposite, which is the client only GET from the server that serves some payload.
I also saw many issues asked related to block transfer examples. It would be helpful to tackle this problem together for the examples code.
Hi,
Blockwise transfers are enabled by default for both DTLS and UDP. To use blockwise, simply send a POST or PUT request. Here's an example:
Client
package main
import (
"bytes"
"context"
"log"
"os"
"time"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/udp"
)
func main() {
co, err := udp.Dial("localhost:5688")
if err != nil {
log.Fatalf("Error dialing: %v", err)
}
path := "/a"
if len(os.Args) > 1 {
path = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := co.Post(ctx, path, message.TextPlain, bytes.NewReader(make([]byte, 1024*1024)))
if err != nil {
log.Fatalf("Error sending request: %v", err)
}
log.Printf("Response payload: %v", resp.String())
}
Server
package main
import (
"bytes"
"io"
"log"
coap "github.com/plgd-dev/go-coap/v3"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/plgd-dev/go-coap/v3/mux"
)
func loggingMiddleware(next mux.Handler) mux.Handler {
return mux.HandlerFunc(func(w mux.ResponseWriter, r *mux.Message) {
log.Printf("ClientAddress %v, %v\n", w.Conn().RemoteAddr(), r.String())
next.ServeCOAP(w, r)
})
}
func handleRequest(w mux.ResponseWriter, r *mux.Message) {
customResp := w.Conn().AcquireMessage(r.Context())
defer w.Conn().ReleaseMessage(customResp)
if r.Body() != nil {
data, err := io.ReadAll(r.Body())
if err != nil {
log.Printf("Cannot read body: %v", err)
return
}
log.Printf("Received length: %v", len(data))
}
customResp.SetCode(codes.Changed)
customResp.SetToken(r.Token())
customResp.SetContentFormat(message.TextPlain)
customResp.SetBody(bytes.NewReader([]byte("Response from server")))
err := w.Conn().WriteMessage(customResp)
if err != nil {
log.Printf("Cannot set response: %v", err)
}
}
func main() {
router := mux.NewRouter()
router.Use(loggingMiddleware)
router.Handle("/a", mux.HandlerFunc(handleRequest))
log.Fatal(coap.ListenAndServe("udp", ":5688", router))
}
Additional Configuration
To customize blockwise behavior, use the option provided in WithBlockwise. Configure the server via coap.ListenAndServeWithOptions and the client via Dial similar as is in the example. Also there is a limit for max message size (64KB by default) so If you want to send 1MB you need to set also the option WithMaxMessageSize to 1024*1024.
Hi Jozef, thank you for your response, I will try it.
I also figured it out today from the simple examples,
it would be nice if we put our code to the examples, to help others as references.
Client
package main
import (
"bytes"
"context"
"log"
"os"
"time"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/net/blockwise"
"github.com/plgd-dev/go-coap/v3/options"
"github.com/plgd-dev/go-coap/v3/udp"
)
func main() {
// Configure blockwise options: enable=true, block size=SZX1024, timeout=5s
blockwiseOpt := options.WithBlockwise(true, blockwise.SZX1024, 5*time.Second)
client, err := udp.Dial("127.0.0.1:5683", blockwiseOpt)
if err != nil {
log.Fatalf("Error dialing: %v", err)
}
path := "/big-endpoint"
if len(os.Args) > 1 {
path = os.Args[1]
}
// create a 1024-byte payload
payload := make([]byte, 1024)
for i := 0; i < 1024; i++ {
payload[i] = byte(i % 256) // Fill with example data
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := client.Post(ctx, path, message.TextPlain, bytes.NewReader(payload))
if err != nil {
log.Fatalf("Error sending request: %v", err)
}
log.Printf("Response payload: %v", resp.String())
}
Server
package main
import (
"bytes"
"log"
coap "github.com/plgd-dev/go-coap/v3"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/plgd-dev/go-coap/v3/mux"
)
func loggingMiddleware(next mux.Handler) mux.Handler {
return mux.HandlerFunc(func(w mux.ResponseWriter, r *mux.Message) {
log.Printf("ClientAddress %v, %v\n", w.Conn().RemoteAddr(), r.String())
next.ServeCOAP(w, r)
})
}
func handleA(w mux.ResponseWriter, r *mux.Message) {
err := w.SetResponse(codes.Content, message.TextPlain, bytes.NewReader([]byte("success")))
if err != nil {
log.Printf("cannot set response: %v", err)
}
}
func handleB(w mux.ResponseWriter, r *mux.Message) {
customResp := w.Conn().AcquireMessage(r.Context())
defer w.Conn().ReleaseMessage(customResp)
customResp.SetCode(codes.Content)
customResp.SetToken(r.Token())
customResp.SetContentFormat(message.TextPlain)
customResp.SetBody(bytes.NewReader([]byte("B hello world")))
err := w.Conn().WriteMessage(customResp)
if err != nil {
log.Printf("cannot set response: %v", err)
}
}
func main() {
r := mux.NewRouter()
r.Use(loggingMiddleware)
r.Handle("/big-endpoint", mux.HandlerFunc(handleA))
r.Handle("/b", mux.HandlerFunc(handleB))
log.Fatal(coap.ListenAndServe("udp", "127.0.0.1:5683", r))
}
how to set the blocksize to 512 in v3? it seems udp.WithBlockwise is removed?
my bad, got it
how to set the blocksize to 512 in v3? it seems udp.WithBlockwise is removed?