Since the latest weekly release, closing a websocket connection results
in two possible return codes: EOF (the one as before) or "connection
reset by peer". (The previous release always delivers only EOF.)
Before filing an issue, is this maybe intended behaviour?
Here is the example server and client; running the client again and
again results in one of the above error codes:
--- Server ---
package main
import (
"fmt"
"http"
"websocket"
)
func server(ws *websocket.Conn) {
fmt.Printf("new connection\n")
buf := make([]byte, 100)
for {
if _, err := ws.Read(buf); err != nil {
fmt.Printf("%s", err.String())
break
}
}
fmt.Printf(" => closing connection\n", )
ws.Close()
}
func main() {
http.Handle("/websocket", websocket.Handler(server))
err := http.ListenAndServe(":12345", nil)
if err != nil {
panic("ListenAndServe: " + err.String())
}
}
--- Client ---
package main
import (
"fmt"
"time"
"websocket"
)
func main() {
ws, err := websocket.Dial("ws://localhost:12345/websocket", "",
"http://localhost/")
if err != nil {
panic("Dial: " + err.String())
}
go readFromServer(ws)
fmt.Printf("Expecting EOF: ")
ws.Close()
time.Sleep(60000000000)
}
func readFromServer(ws *websocket.Conn) {
buf := make([]byte, 1000)
for {
if _, err := ws.Read(buf); err != nil {
fmt.Printf("%s\n", err.String())
break
}
}
}
bye
Norbert
Hi,
Since the latest weekly release, closing a websocket connection results in two possible return codes: EOF (the one as before) or "connection reset by peer". (The previous release always delivers only EOF.)
Before filing an issue, is this maybe intended behaviour?
Here is the example server and client; running the client again and again results in one of the above error codes:
> I think
> EOF when it received the close frame
> ECONNRESET when it finds the underlying connection is closed.
Is this distinction really necessary? This would mean i always have to
check for two errors instead of one (to distinguish between a real error
and an actual EOF).
> Note that a websocket instance should be used on single goroutine.
> (client program calls Read and Close on other goroutines)
This won't be possible, as Read() is a blocking function and while
waiting for incoming data, i need to check whether the websocket
connection should be disconnected. This can only be done in a seperate
go routine, as the other is blocked..
Norbert
On 09/05/2011 10:50 AM, Fumitoshi Ukai (鵜飼文敏) wrote:Is this distinction really necessary? This would mean i always have to check for two errors instead of one (to distinguish between a real error and an actual EOF).
I think
EOF when it received the close frame
ECONNRESET when it finds the underlying connection is closed.
This won't be possible, as Read() is a blocking function and while waiting for incoming data, i need to check whether the websocket connection should be disconnected. This can only be done in a seperate go routine, as the other is blocked..
Note that a websocket instance should be used on single goroutine.
(client program calls Read and Close on other goroutines)
Norbert
>> Is this distinction really necessary? This would mean i always have to
>> check for two errors instead of one (to distinguish between a real error and
>> an actual EOF).
>
>
> I think so. Why not?
Because untill weekly.2011-09-01, there was no such distinction, and
only an EOF was delivered in either case. Now i would have to rewrite
all my code to check not only for EOF, but also for ECONNRESET. This is
not such a big effort, but i think it's rather ugly.
And as my example shows, there is not a reliable error return code. EOF
or ECONNRESET are returned on a random base (presumably some race
condition, which i have no way to control), although the connection was
always closed with Close().
I have to admit, my example was not that good, as Read() and Close()
werde called at the same time, but delaying the Close() does not fix the
problem; a better client example can be seen below.
>> Note that a websocket instance should be used on single goroutine.
>>> (client program calls Read and Close on other goroutines)
Can you give an example program that opens a websocket connection, reads
data from it and closes the connection after 5 seconds - in a single go
routine?
> Close doesn't block for close. Close just initiates closing handshake and
> close the connection.
Yes, and after such a clean connection shutdown, i would expect to
always receive EOF from the waiting Read(). Or when not EOF, at least a
different but constant error.
> How did you check the connection should be disconnected?
User interaction, timeout, some other connection gets closed - there may
exist many reasons why i want to have the websocket connection closed.
In this example this is a timeout of 2 seconds (the server is the same):
package main
import (
"fmt"
"time"
"websocket"
)
func main() {
for {
ws, err := websocket.Dial("ws://localhost:12345/websocket", "",
"http://localhost/")
if err != nil {
panic("Dial: " + err.String())
}
done := make(chan int)
go readFromServer(ws, done)
time.Sleep(2000000000) // 2s
fmt.Printf("Expecting EOF: ")
ws.Close()
<-done
time.Sleep(1000000000) // 1s
}
}
func readFromServer(ws *websocket.Conn, done chan int) {
buf := make([]byte, 1000)
for {
if _, err := ws.Read(buf); err != nil {
fmt.Printf("%s\n", err.String())
break
}
}
done <- 1
}
bye
Norbert
On 09/06/2011 03:29 AM, Fumitoshi Ukai (鵜飼文敏) wrote:Because untill weekly.2011-09-01, there was no such distinction, and
>> Is this distinction really necessary? This would mean i always have to
>> check for two errors instead of one (to distinguish between a real error and
>> an actual EOF).
>
>
> I think so. Why not?
only an EOF was delivered in either case. Now i would have to rewrite
all my code to check not only for EOF, but also for ECONNRESET. This is
not such a big effort, but i think it's rather ugly.
And as my example shows, there is not a reliable error return code. EOF
or ECONNRESET are returned on a random base (presumably some race
condition, which i have no way to control), although the connection was
always closed with Close().
I have to admit, my example was not that good, as Read() and Close()
werde called at the same time, but delaying the Close() does not fix the
problem; a better client example can be seen below.
Can you give an example program that opens a websocket connection, reads
>> Note that a websocket instance should be used on single goroutine.
>>> (client program calls Read and Close on other goroutines)
data from it and closes the connection after 5 seconds - in a single go
routine?
Yes, and after such a clean connection shutdown, i would expect to
> Close doesn't block for close. Close just initiates closing handshake and
> close the connection.
always receive EOF from the waiting Read(). Or when not EOF, at least a
different but constant error.
> Older version of websocket protocol didn't have closing handshake.
Ok, didn't know this.
> Now, it will return an error code of underlying Read, or returns EOF if it
> got closing handshake.
But then there is something wrong with the implementation. A Close() on
the client side should (at least in this simple example on a local
machine) always complete the closing handshake without error, thus the
Read() should always receive an EOF and nothing else. Why should the
underlying Read() in the closing handshake suddenly get an error on a
connection, which was working perfectly so far?
I found out what causes the generation of ECONNRESET; it's the Close()
on the server side. At the time the server calls Close(), the closing
handshake should have completed a while back. Is it possible that the
websocket connection (on the client side) goes first into a somewhat
"websocket closed" state, and the subsequent disconnect of the TCP
connection overrides this sane state with a ECONNRESET?
>> Can you give an example program that opens a websocket connection, reads
>> data from it and closes the connection after 5 seconds - in a single go
>> routine?
>>
>
> ws.SetReadTimeout(5 * 1000*1000*1000), then ws.Read() ?
Ok, i have to change the task to:
Can you give an example program that opens a websocket connection, reads
data from it and when the user hits return, it closes the connection?
bye
Norbert
On 09/06/2011 12:17 PM, Fumitoshi Ukai (鵜飼文敏) wrote:Ok, didn't know this.
Older version of websocket protocol didn't have closing handshake.
But then there is something wrong with the implementation. A Close() on the client side should (at least in this simple example on a local machine) always complete the closing handshake without error, thus the Read() should always receive an EOF and nothing else. Why should the underlying Read() in the closing handshake suddenly get an error on a connection, which was working perfectly so far?
Now, it will return an error code of underlying Read, or returns EOF if it
got closing handshake.
I found out what causes the generation of ECONNRESET; it's the Close() on the server side. At the time the server calls Close(), the closing handshake should have completed a while back. Is it possible that the websocket connection (on the client side) goes first into a somewhat "websocket closed" state, and the subsequent disconnect of the TCP connection overrides this sane state with a ECONNRESET?
Ok, i have to change the task to:
Can you give an example program that opens a websocket connection, reads
data from it and closes the connection after 5 seconds - in a single go
routine?
ws.SetReadTimeout(5 * 1000*1000*1000), then ws.Read() ?
data from it and when the user hits return, it closes the connection?
Can you give an example program that opens a websocket connection, reads
bye
Norbert
> if we call ws.Read in other goroutine of ws.Close, Read will be called
> somewhere
> before calling ws.Close
> before sending closing handshake
> after sending closing handshake
> before receiving closing handshake
> after receiving closing handshake
> after underlying socket is closed
This is generally correct, but in this particular example, there is this
delay of 2 seconds between running the go function and closing the
connection. It can be safely assumed that after 2 seconds, the Read() is
already waiting for incoming data. So from all your mentioned situations
only one remains:
before calling ws.Close
(I just tried it with the delay increased to 10s, still the same result...)
If the process is in a well defined starting state - main process is
waiting with Sleep(), go process is waiting in Read() - and the Read
receives EOF or ECONNRESET on a random base, a distinction between those
two error codes is actually worth nothing; we always have to check for
EOF and ECONNRESET as a clean connection shutdown, but cannot tell
something specific when this or that error returned. Receiving
ECONNRESET does not mean "There was this special situation that we did
not receive EOF, but ECONNRESET, and i should print a warning or
something", but it does mean "We received ECONNRESET, but it could also
have been EOF as well".
> note that receiving closing handshake is optional. It might close the
> underlying socket before receiving closing handshake.
Does any user need to know whether there was a final closing handshake
or not? Anyway, the user can't determine from the error code whether
there was a closing handshake or not, as explained before.
>> I found out what causes the generation of ECONNRESET; it's the Close() on
>> the server side. At the time the server calls Close(), the closing handshake
>> should have completed a while back. Is it possible that the websocket
>> connection (on the client side) goes first into a somewhat "websocket
>> closed" state, and the subsequent disconnect of the TCP connection overrides
>> this sane state with a ECONNRESET?
>
>
> Hmm, is it worth to do it?
> we need to add the error check in every where in websocket code.
There are six functions in the websocket package who return an os.Error
at all. Three functions of them return an error related to connections:
Read, Write and Close.
> I think API user can simply handle such error as connection close.
So you are moving the error check in three functions inside of the
websocket package to outside of the websocket package. Every existing
code using websockets in the whole world must be updated, and all code
written in the future has to check for two errors instead of a usual one.
As i mentioned once before, the websocket version prior to this release
never returned ECONNRESET, and also didn't check for it, why is this now
the case? Is it maybe the net package that behaves different now?
>> Can you give an example program that opens a websocket connection, reads
>> data from it and when the user hits return, it closes the connection?
>>
>
> I'm not sure this is the best way...
Polling for input is one of the worst ways for sure.
bye
Norbert