Skip to content

[doc] Please document how to handle websocket.NetConn().Read() return zero and nil  #353

Closed
@bronze1man

Description

@bronze1man

I just wrote a demo to test it. Here is my code:

package main

import (
	"net/http"
	"io"
	"fmt"
	"nhooyr.io/websocket"
	"context"
	"time"
	"strconv"
)

func main(){
	go func(){
		http.ListenAndServe(`127.0.0.1:9098`,echoServer{})
	}()
	time.Sleep(time.Millisecond*10)
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	c, _, err := websocket.Dial(ctx, `http://127.0.0.1:9098`, &websocket.DialOptions{
		Subprotocols: []string{"echo"},
	})
	defer c.Close(websocket.StatusNormalClosure,``)
	ctx = context.Background()
	inList:=[]byte{1}
	buf:=make([]byte,1024)
	c2:=websocket.NetConn(ctx,c,websocket.MessageBinary)
	for i:=0;i<10;i++{
		_,err=c2.Write(inList)
		if err!=nil{
			panic(err)
		}
		nr,err := c2.Read(buf)
		if err!=nil{
			panic(err)
		}
		if nr==0{
			panic(`nr==0 `+strconv.Itoa(i))
		}
	}
}

// echoServer is the WebSocket echo server implementation.
// It ensures the client speaks the echo subprotocol and
// only allows one message every 100ms with a 10 message burst.
type echoServer struct {
	// logf controls where logs are sent.
	logf func(f string, v ...interface{})
}

func (s echoServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
		Subprotocols: []string{"echo"},
	})
	if err != nil {
		s.logf("%v", err)
		return
	}
	defer c.Close(websocket.StatusInternalError, "the sky is falling")
	if c.Subprotocol() != "echo" {
		c.Close(websocket.StatusPolicyViolation, "client must speak the echo subprotocol")
		return
	}
	for {
		err = echo(r.Context(), c)
		if websocket.CloseStatus(err) == websocket.StatusNormalClosure {
			return
		}
		if err != nil {
			s.logf("failed to echo with %v: %v", r.RemoteAddr, err)
			return
		}
	}
}

// echo reads from the WebSocket connection and then writes
// the received message back to it.
// The entire function has 10s to complete.
func echo(ctx context.Context, c *websocket.Conn) error {
	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()

	typ, r, err := c.Reader(ctx)
	if err != nil {
		return err
	}

	w, err := c.Writer(ctx, typ)
	if err != nil {
		return err
	}

	_, err = io.Copy(w, r)
	if err != nil {
		return fmt.Errorf("failed to io.Copy: %w", err)
	}

	err = w.Close()
	return err
}

And I found that websocket.NetConn().Read() will return zero and nil .
I never seen a net.Conn object work like this.
I do not know how to do with it , skip? But I am afraid of unlimit loop...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions