-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Websocket ping pong timeout #866
Comments
Control messages like PING are processed when reading a message. Ensure that the client reads all messages.
NextReader and NextWriter are the core functionality ReadMessage is a helper method for getting a reader using NextReader and reading from that reader to a buffer. WriteMessage is a helper method for getting a writer using NextWriter, writing the message and closing the writer.
Because your application does not write control messages concurrently with calls to WriteMessage / NextWriter, there's no need to use WriteControl in your application. Applications should write with a deadline to protect against peers that do not read from the socket. |
Hi @pennystevens, Thanks for getting back to me to provide clarity on this.
I'm running the app in a
func getWSConn(u *userdom.User, roomID string) (*websocket.Conn, error) {
conn, _, err := websocket.DefaultDialer.Dial("wss://localhost:8090/ws...", nil)
conn.SetPingHandler(func(data string) error {
println("RECEIVED PING") // OK
return conn.WriteMessage(websocket.PongMessage, []byte{})
})
return conn, err
} ... and the creation of the PONG handler in the app: func createWS(w http.ResponseWriter, r *http.Request, pongHandler pongHandler) (*websocket.Conn, error) {
// ...
conn.SetPongHandler(pongHandler)
return conn, nil
}
// ...
// Respond to ping tick and reset the timer
func (c *WSClient) pongHandler(pongMsg string) error {
log.Print("PONG") // NOT REACHED
return c.wsconn.SetReadDeadline(time.Now().UTC().Add(pongWait))
} Is there something I'm missing? |
I noticed some problems with the code in issue. This code:
will never report a ping or pong message because ReadMessage only returns data messages (text, binary). Control messages are handled by callbacks or, in the case of close, the error return value. The ping handler:
has three problems.
Fix the ping handler by starting from the default ping handler code:
The previous comment sets the pong handler to |
I'm having a similar issue but not exactly the same. My pong handler is never called so the connection is closed on keep alive timeout. I am unsure if this is an issue with the lib, my implementation or the server I am connecting to. I have been trying to disable the ping's from my server in case it is the later but with no luck. // pong handler
r.serverWebsocket.SetPongHandler(func(data string) error {
r.serverWebsocket.SetReadDeadline(time.Now().Add(pongWait))
slog.Debug("Received pong from server", "data", data)
return nil
})
// ping handler
r.serverWebsocket.SetPingHandler(func(data string) error {
slog.Debug("Received ping from server", "data", data)
err := r.serverWebsocket.WriteControl(websocket.PongMessage, []byte(data), time.Now().Add(writeWait))
if err == websocket.ErrCloseSent {
return nil
} else if e, ok := err.(net.Error); ok && e.Temporary() {
return nil
}
return err
}) error I keep getting: {"time":"2025-01-08T16:54:21.527656997+01:00","level":"DEBUG","msg":"Error reading from Server WebSocket","error":"websocket: close 1011 (internal server error): keepalive ping timeout"} |
@Oudwins Does your application send pings to the peer? Your ping handler is unnecessary. |
@hulkingshtick I'm not manually sending any pings. So I assumed that gorilla is sending them under the hood? The ping handler (from the godoc comment) triggers when the client sends a ping. I assumed that means that when the server I connect to sends a ping? I copied the default ping handler just to add a log to check if the server I am connecting to sends ping's. It does appear to since I do get those logs edit: also, thank you. I can't believe you replied so fast, happy new year! and massive thank you |
The package does not send pings under the hood. The application must send a ping to receive a pong. The package does respond to pings by sending a pong. |
Then do you know what could cause me to get this error if I am not sending any pings? websocket: close 1011 (internal server error): keepalive ping timeout I'm seriously confused. I keep getting that error approximately every 80 seconds or so. Edit: im just looking through the logs on my load tests and it is exactly every 81s super weird |
Does your application contain the text Based on the information shared here, your application must send PINGs. Your application advances the read deadline in response to a received PONG. The peer sends a PONG in response to a received PING. If your application does not send a PINGs, then your application does not receive PONGs. If your application does not receive PONGs, then your application does not advance the read deadline. |
My app code does not contain the text keepalive anywhere. The logs contain multiple received ping logs but no received pong logs To be clear I have some more code that advances the read deadline elsewhere if that is relevant. Because the long handler is never called |
If your application does not contain the text
That is expected because:
The your application must send a PING to receive a PONG. |
Right, right. I am now sending pings every 5 seconds and receiving pongs back no issue. But the connection still gets closed with the previously mentioned error every 80.5 seconds or so. Is there some way I can verify that this is an error being sent by the peer application? |
you have to implement pong. browser does ping on its own(and it will not show in console). it took me a while to figure out how to do it. because this library is truly "bare bones". but the horrible DX is most likely the effect of the spec rather than library itself. iirc you have to a) enable pong(i think setting pong function to nil should trigger default behavior) and b) you have to have reader and listener running. even if you need only one, otherwise ping/pong mechanism is not handled due to the nature of how this library works(there is only one connection and the library determines message type from frame type, so if you are not listening and writing, the ping/pong frames on both sides will not be processed). |
Hi guys,
I'm trying to build a chat app that looks like the below simplified version.
What the chat app is doing:
What the stress-test script is doing
Problem
The stress-test script receives a PING frame and tries to send a PONG one but I see no incoming PONG frame in the chat app and the connection is then timed out.
wsconn.ReadMessage() error: read tcp 127.0.0.1:8090->127.0.0.1:55896: i/o timeout
Subsidiary questions
ReadMessage/WriteMessage
vsNextReader/NextWriter
?WriteMessage
to send control frames. I saw that there's alsoWriteControl
that takes a deadline and then callsSetWriteDeadline
. I know that unlikeWriteMessage
,WriteControl
is safe to be used concurrently. The thing is my chat app, I only set a read deadline cause the "idleness" of a connection is detected when the user leaves, so from a server-side perspective, when there's no more data to be read. I don't know how am I supposed to useWriteControl
in this context.error:websocket: close 1006 (abnormal closure): unexpected EOF
.What can cause this issue cause I don't have much log?
Originally posted by @BigBoulard in gorilla/.github#26
The text was updated successfully, but these errors were encountered: