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

x/net/websocket: Read returns partial frames #6093

Closed
gopherbot opened this issue Aug 9, 2013 · 4 comments
Closed

x/net/websocket: Read returns partial frames #6093

gopherbot opened this issue Aug 9, 2013 · 4 comments
Milestone

Comments

@gopherbot
Copy link

@gopherbot gopherbot commented Aug 9, 2013

by keith.rollin:

I am using "go version go1.1.1 darwin/amd64" on a 2009 vintage iMac using an
up-to-date Mac OS X 10.8.4. I am using go.net/websocket from a couple of weeks ago. I
have checked that there have been no updates to the package since then. I've searched
all issues for "websocket" -- open and closed -- but don't find any discussion
on the problem I'm having.

I am using go to write a websocket client to test a websocket server I'm writing. The
test client is written in go, and the server I'm testing is written in C++ using
libwebsocket, running on CentOS 5.7 with linux 2.6.18. Part of the protocol I'm
implementing over websocket includes both the client and server sending PING/PONG
messages every few seconds. Note that these are NOT WebSocket Ping/Pong packets. I am
not using those because of incomplete Ping/Pong support in the contexts in which both my
server and clients run.

Every few seconds, the client and server will send the other a standard TEXT frame with
the following contents:

PING<timestamp>

In response, the receiving side sends back

PONG<timestamp from the PING message>

For implementation reasons, the <timestamp> from the PINGs the server sends is in
milliseconds and is 13 digits long, and the <timestamp> from the PINGs the client
sends is in nanoseconds and is 19 digits long. This information may be relevant, as well
see later.

I noticed that, every once and a while, when the client would call
websocket.Read(buffer) (where buffer is a 5K byte buffer), that it would receive just
"PONG" without any timestamp. On the next call to Read(), it would get the
timestamp.

Checking my server's logs and using tcpdump, I see that this happens when the server is
both sending its own PING<timestamp> and responding to a client's PING by sending
a PONG<timestamp> at nearly the same time. That is, the server is writing
something like:

Frame 1: <0x81><0x11>PING1376035994244
Frame 2: <0x81><0x17>PONG1376035994222985405

If these happen in close proximity to each other, however, the actual TCP packets look
like:

Packet 1: <0x81><0x11>PING1376035994244<0x81><0x17>PONG
Packet 2: 1376035994222985405

For some reason, TCP is sending the data in packets that don't align with the websocket
framing or with the socket send() calls that libwebsocket is making. For some reason, it
appears to be using the length of Frame 2 when sending the contents of the socket buffer
-- note that Packet 1 includes six bytes more than you'd expect, and that Frame 2 is six
bytes longer than Frame 1.

go.net/websocket responds to these packets by returning the following on successive
calls to websocket.Read():

Result 1: PING1376035994244
Result 2: PONG
Result 3: 1376035994222985405

When my client code sees this sequence, it flags it as invalid. It's flexible enough to
deal with the PONG message that doesn't have a timestamp, but it has no idea what to do
with the 1376035994222985405.

I have three comments here:

First, I don't think that the PONG message should be returned by websocket.Read in two
parts. go.net/websocket knows the length of the frame and should return the whole thing
to my client application.

Second, given the current behavior, I don't see a way for me to workaround it and
determine that Result 2 represents an incomplete frame and that it should be glued with
Result 3 before trying to process the combined result.

Third, I wonder if there's a related issue here. The documentation for websocket.Read
says that it will only return as much information as is available in the buffer passed
to Read, and that if there is more information, the application can call websocket.Read
again. However, there is no facility for telling the caller that there *is* more
information -- that the caller received only a partial frame and that the subsequent
Read will return the rest (or more) of it rather than data from a subsequent frame.

Because of these issues -- particularly the first two -- I'm at a loss to know how to
update my go-based client program to account for my frame data being split up.
@gopherbot
Copy link
Author

@gopherbot gopherbot commented Aug 10, 2013

Comment 1 by keith.rollin:

Another related issue just occurred. I tried sending a message from the server to the
client that was more than 1500 bytes long. This caused it to get broken up into multiple
Ethernet packets, which I received on the client one at a time. Again, I have no way of
knowing to reconstitute these pieces. I suppose I could add my own framing, but I
thought WebSocket was supposed to do that for me.
@robpike
Copy link
Contributor

@robpike robpike commented Aug 14, 2013

Comment 3:

Unfortunate property of streaming protocols. As Gary Burd says, use some sort of framing
or delimiters.

Status changed to WorkingAsIntended.

@gopherbot
Copy link
Author

@gopherbot gopherbot commented Aug 14, 2013

Comment 4 by keith.rollin:

Thanks for the response. Actually, I moved to github.com/garyburd/go-websocket/websocket
before Gary posted his response. I suppose it gets around this property of streaming
protocols by using a slightly different interface. But it was dead simple to switch to
it, so it works well for me.
@mikioh mikioh added repo-net and removed repo-net labels Dec 23, 2014
@mikioh mikioh changed the title go.net/websocket: Read returns partial frames websocket: Read returns partial frames Jan 4, 2015
@rsc rsc added this to the Go1.2 milestone Apr 14, 2015
@rsc rsc removed the go1.2maybe label Apr 14, 2015
@mikioh mikioh changed the title websocket: Read returns partial frames x/net/websocket: Read returns partial frames Jul 30, 2015
@mikioh mikioh modified the milestones: Go1.2, Unreleased Jul 30, 2015
@golang golang locked and limited conversation to collaborators Aug 5, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.