一个websocket连接为什么不能有多个goroutine访问

林深时见鹿 海蓝时见鲸 梦醒时见你

今天在看源码时看到的,分享出来。

所用的websocket库:github.com/gorilla/websocket

代码位置:rancher/vendor/github.com/gorilla/websocket/conn.go,WriteMessage方法

// WriteMessage is a helper method for getting a writer using NextWriter,
// writing the message and closing the writer.
func (c *Conn) WriteMessage(messageType int, data []byte) error {
	wr, err := c.NextWriter(messageType)
	if err != nil {
		return err
	}
	w := wr.(messageWriter)
	if _, err := w.write(true, data); err != nil {
		return err
	}
	if c.writeSeq == w.seq {
		if err := c.flushFrame(true, nil); err != nil {
			return err
		}
	}
	return nil
}

看下510行的NextWriter方法:

// NextWriter returns a writer for the next message to send.  The writer's
// Close method flushes the complete message to the network.
//
// There can be at most one open writer on a connection. NextWriter closes the
// previous writer if the application has not already done so.
//
// The NextWriter method and the writers returned from the method cannot be
// accessed by more than one goroutine at a time.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
	if c.writeErr != nil {
		return nil, c.writeErr
	}

	if c.writeFrameType != noFrame {
		if err := c.flushFrame(true, nil); err != nil {
			return nil, err
		}
	}

	if !isControl(messageType) && !isData(messageType) {
		return nil, errBadWriteOpCode
	}

	c.writeFrameType = messageType
	return messageWriter{c, c.writeSeq}, nil
}

注意注释说明。即:1,一个连接上最多可以有一个打开的的writer。 如果程序未关闭,则NextWriter将关闭前一个writer,如下:

   if c.writeErr != nil {
 	return nil, c.writeErr
   }

一次不能由多个goroutine访问NextWriter方法和从该方法返回的writer(多个的话将产生多个writer)

再看看reader,一样的:

// NextReader returns the next data message received from the peer. The
// returned messageType is either TextMessage or BinaryMessage.
//
// There can be at most one open reader on a connection. NextReader discards
// the previous message if the application has not already consumed it.
//
// The NextReader method and the readers returned from the method cannot be
// accessed by more than one goroutine at a time.
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {

	c.readSeq++
	c.readLength = 0

	for c.readErr == nil {
		frameType, err := c.advanceFrame()
		if err != nil {
			c.readErr = hideTempErr(err)
			break
		}
		if frameType == TextMessage || frameType == BinaryMessage {
			return frameType, messageReader{c, c.readSeq}, nil
		}
	}
	return noFrame, nil, c.readErr
}

后续继续详细跟进。

发布了172 篇原创文章 · 获赞 114 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/HYZX_9987/article/details/104312831