Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
bronze1man opened this issue Nov 3, 2022 · 1 comment

Comments

@bronze1man
Copy link

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...

@nhooyr
Copy link
Owner

nhooyr commented Mar 5, 2023

#367

Yes you always have to check n, if n is zero you just keep going.

@nhooyr nhooyr closed this as completed Mar 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants