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

Writing data more frequently will cause panic #182

Closed
pangdahua opened this issue Jul 3, 2017 · 20 comments
Closed

Writing data more frequently will cause panic #182

pangdahua opened this issue Jul 3, 2017 · 20 comments
Labels

Comments

@pangdahua
Copy link

发现如果数据发送的比较频繁,会导致与ping的数据写时并发,go race 在大量的客户端的情况下,会引起websocket的写并发panic。

@googollee
Copy link
Owner

Show me the code

@pangdahua
Copy link
Author

pangdahua commented Jul 5, 2017

image

I want realize broadcast.

When delete engine.io/session.go line 75 ping code, look ok.

thk

@googollee
Copy link
Owner

Will you give me a complete demo code, which can reproduce this issue? It's hard to figure out what you want to do from an image.

@pangdahua
Copy link
Author

pangdahua commented Jul 25, 2017

package main

import (
	"gopkg.in/googollee/go-socket.io.v1"
	"gopkg.in/googollee/go-engine.io.v1"
	"gopkg.in/googollee/go-engine.io.v1/transport/websocket"
	"gopkg.in/googollee/go-engine.io.v1/transport"
	"log"
	"net/http"
	"sync"
	"time"
	"github.com/golang/glog"
	"flag"
	"runtime"
)

func init() {
	flag.Parse()
}

type DemoServer struct {
	io *socketio.Server
	clients map[string]socketio.Conn // connections
	_rw sync.RWMutex
}

func NewServer() *DemoServer {
	var server *DemoServer
	var io *socketio.Server
	var err error

	eioOption := &engineio.Options{
		Transports:[]transport.Transport {
			websocket.Default,
		},
		PingTimeout:time.Second * 30,
		PingInterval: time.Microsecond * 5,
	}

	io, err = socketio.NewServer(eioOption)

	if err != nil {
		log.Fatal("start socketio server error:", err)
	}

	server = &DemoServer{
		io: io,
		clients: make(map[string]socketio.Conn, 1024),
	}

	server.ioCallback()
	go server.broadcast()
	return server
}

// define socketio event callback
func (self *DemoServer) ioCallback() {
	self.io.OnConnect("/socket.io/", func(conn socketio.Conn) error {
		glog.Infof("client %s connect on server", conn.ID())
		self._rw.Lock()
		defer self._rw.Unlock()
		self.clients[conn.ID()] = conn

		return nil
	})

	self.io.OnEvent("/socket.io/", "demo", func(conn socketio.Conn, msg string) {
		glog.Infof("client %s say %s", conn.ID(), msg)
	})
}

// broadcast all client
func (self *DemoServer) broadcast() {
	for {
		for _, client := range self.clients {
			client.Emit("demo", "hello "+client.ID())
		}

		time.Sleep(time.Second * 1)

		runtime.Gosched()
	}
}

func (self *DemoServer) Serve() {
	go self.io.Serve()
}

func (self *DemoServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	self.io.ServeHTTP(w, r)
}



func main() {
	defer glog.Flush()

	server := NewServer()

	go server.Serve()
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./")))
	http.ListenAndServe(":8000", nil)
}

============

socketio.client.html

<!doctype html>
<html>
<head>
    <title>Socket.IO chat</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font: 13px Helvetica, Arial; }
        form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
        form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
        form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
        #messages { list-style-type: none; margin: 0; padding: 0; }
        #messages li { padding: 5px 10px; }
        #messages li:nth-child(odd) { background: #eee; }
    </style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
    <input id="m" autocomplete="off" /><button>Send</button>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.4/socket.io.min.js"></script>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

<script>
    var socket = io("http://127.0.0.1:8000/socket.io/", {
        transports:['websocket']
    });

    socket.emit('demo', JSON.stringify({"symbol":["RB1709"]}))
    socket.on("demo", function (data) {
        console.log(data)
    })

    /**
     socket.emit('msg', 'hello');
     var s2 = io("/subscribe");

     socket.on('reply', function(msg){
            console.log(msg)
            $('#messages').append($('<li>').text(msg));
        });
     $('form').submit(function(){
            s2.emit('msg', $('#m').val(), function(data){
                $('#messages').append($('<li>').text('ACK CALLBACK: ' + data));
            });
            socket.emit('notice', $('#m').val());
            $('#m').val('');
            return false;
        });*/
</script>
</body>
</html>

@pangdahua
Copy link
Author

that would trigger panic: concurrent write to websocket connection.
PingInterval time short, would increase panic.
I guess go-engine.io.v1/session.go line 77 cause

thx

@madarou
Copy link

madarou commented Aug 8, 2017

@pangdahua @googollee I met the same issue. Have you fix this(not by comment out PING message)

@madarou
Copy link

madarou commented Aug 8, 2017

why use RLock() when write message in /go-engine.io.v1/session.go, why not use Lock()? @googollee

for {
		s.upgradeLocker.RLock()
		w, err := s.conn.NextWriter(ft, pt)
		if err != nil {
			s.upgradeLocker.RUnlock()
			if op, ok := err.(payload.Error); ok {
				if op.Temporary() {
					continue
				}
			}
			return nil, err
		}
		return newWriter(w, &s.upgradeLocker), nil
	}

@jackingzhao
Copy link

@googollee
确实会存在这样的状况

panic: concurrent write to websocket connection

goroutine 22 [running]:
github.com/gorilla/websocket.(*messageWriter).flushFrame(0xc04213ce00, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0)
D:/GoPath/src/github.com/gorilla/websocket/conn.go:589 +0x608
github.com/gorilla/websocket.(*messageWriter).Close(0xc04213ce00, 0xc04223bc38, 0x18)
D:/GoPath/src/github.com/gorilla/websocket/conn.go:703 +0x67
github.com/googollee/go-engine%2eio.(*writer).Close(0xc0421ccd80, 0x0, 0x0)
E:/qpsj/svn/sss_svr/server/src/github.com/googollee/go-engine.io/util.go:23 +0x3e
github.com/googollee/go-socket.io/parser.(*Encoder).writePacket(0xc0420ee180, 0xa18420, 0xc0421ccd80, 0x2, 0x0, 0x0, 0x0, 0x0, 0xc0421d8e40, 0x2, ...)
E:/qpsj/svn/sss_svr/server/src/github.com/googollee/go-socket.io/parser/encoder.go:119 +0x38c
github.com/googollee/go-socket.io/parser.(*Encoder).Encode(0xc0420ee180, 0x2, 0x0, 0x0, 0x0, 0x0, 0xc0421d8e40, 0x2, 0x2, 0x0, ...)
E:/qpsj/svn/sss_svr/server/src/github.com/googollee/go-socket.io/parser/encoder.go:35 +0xe0
github.com/googollee/go-socket%2eio.(*conn).serveWrite(0xc0421ee070)
E:/qpsj/svn/sss_svr/server/src/github.com/googollee/go-socket.io/conn.go:171 +0x1e7
created by github.com/googollee/go-socket%2eio.newConn
E:/qpsj/svn/sss_svr/server/src/github.com/googollee/go-socket.io/conn.go:77 +0x385

@jackingzhao
Copy link

因为使用的
conn.go 中
go ret.serveError()
go ret.serveWrite()
go ret.serveRead()

读合写,会同时竞争websocket, 而gorilla的websocket不支持并发操作

gorilla/websocket#119

@pangdahua
Copy link
Author

请问 楼上各位怎么解决的?

@BlackCodes
Copy link

一直不敢升级,下次出稳定版了,记得打个标签!

@qinzhao168
Copy link

请问 楼上用的是什么版本的?

@shiyanlin
Copy link

你们并发读写的问题解决了吗

1 similar comment
@luckzack
Copy link

你们并发读写的问题解决了吗

@luckzack
Copy link

Your application is writing concurrently to a connection. Concurrent writes are not supported. Use a mutex or a goroutine to ensure that there's no more than one writer at a time.

@jjhesk
Copy link

jjhesk commented Feb 7, 2019

你们并发读写的问题解决了吗

@erkie erkie changed the title 1.4 写数据比较频繁会与ping 导致写并发 1.4: Writing data more frequently will cause panic Feb 8, 2019
@erkie erkie removed the v1.4 label Feb 18, 2019
@erkie erkie changed the title 1.4: Writing data more frequently will cause panic Writing data more frequently will cause panic Feb 18, 2019
@wangtuanjie
Copy link

@sshaplygin
Copy link
Collaborator

@wangtuanjie @erkie Is it problem resolved?

@wangtuanjie
Copy link

@wangtuanjie @erkie Is it problem resolved?

sure

@sshaplygin
Copy link
Collaborator

Resolved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests