Sending message from server to client when web socket is opened. #158

Open
tshead2 opened this Issue Feb 8, 2015 · 14 comments

Comments

Projects
None yet
6 participants
@tshead2

tshead2 commented Feb 8, 2015

Gang:

I'm working with the extended chat example (works great out of the box), and trying to send a message from the server to the client when the web socket is initially opened:

    class ChatWebSocketHandler(WebSocket):
      def opened(self):
        cherrypy.engine.publish('add-client', self.username, self)
        self.send("Hello, World!")

However, this causes the web socket to be terminated. I've also tried publishing the message:

    class ChatWebSocketHandler(WebSocket):
      def opened(self):
        cherrypy.engine.publish('add-client', self.username, self)
        cherrypy.engine.publish("websocket-broadcast", "Hello, World!")

... which doesn't terminate the web socket, but doesn't send the message to the newly-connected client either (I assume this is because the broadcast is going out before the handler has been transferred to the WebSocketPlugin pool).

I'm looking to use web sockets for purely one-way publishing of a data feed from server to client(s), so this seems like a pretty basic use-case. What am I missing?

Thanks in advance,
Tim

@Lawouach

This comment has been minimized.

Show comment
Hide comment
@Lawouach

Lawouach Feb 9, 2015

Owner

Hi Tim,

This is a little surprising. Do you have a paste of the termination message? Is there an exception perhaps? Also, which versions of ws4py and cherrypy are you running?

Owner

Lawouach commented Feb 9, 2015

Hi Tim,

This is a little surprising. Do you have a paste of the termination message? Is there an exception perhaps? Also, which versions of ws4py and cherrypy are you running?

@tshead2

This comment has been minimized.

Show comment
Hide comment
@tshead2

tshead2 Feb 9, 2015

I was hoping it was just user error. Here are the versions:

CherryPy 3.2.6
ws4py 0.3.4

Here's the log output when calling self.send() in the opened() callback:

127.0.0.1 - - [09/Feb/2015:09:17:37] "GET / HTTP/1.1" 200 1824 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
[09/Feb/2015:09:17:37]  Handler created: <__main__.ChatWebSocketHandler object at 0x10e1fff90>
127.0.0.1 - - [09/Feb/2015:09:17:37] "GET /ws?username=User96 HTTP/1.1" 101 - "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
[2015-02-09 09:17:37,534] INFO Managing websocket [Local => 127.0.0.1:9000 | Remote => 127.0.0.1:53427]
[2015-02-09 09:17:37,635] ERROR Failed to receive data
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ws4py/websocket.py", line 300, in once
    b = self.sock.recv(self.reading_buffer_size)
error: [Errno 54] Connection reset by peer
[2015-02-09 09:17:37,637] INFO Terminating websocket [Local => 127.0.0.1:9000 | Remote => 127.0.0.1:53427]

It didn't really catch my attention earlier, but I'm not sure why once() would be called by send()? Or is it that send() is somehow leaving things in a bad state, and once() fails when it gets polled by the manager?

Many thanks for the quick response.
Tim

tshead2 commented Feb 9, 2015

I was hoping it was just user error. Here are the versions:

CherryPy 3.2.6
ws4py 0.3.4

Here's the log output when calling self.send() in the opened() callback:

127.0.0.1 - - [09/Feb/2015:09:17:37] "GET / HTTP/1.1" 200 1824 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
[09/Feb/2015:09:17:37]  Handler created: <__main__.ChatWebSocketHandler object at 0x10e1fff90>
127.0.0.1 - - [09/Feb/2015:09:17:37] "GET /ws?username=User96 HTTP/1.1" 101 - "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
[2015-02-09 09:17:37,534] INFO Managing websocket [Local => 127.0.0.1:9000 | Remote => 127.0.0.1:53427]
[2015-02-09 09:17:37,635] ERROR Failed to receive data
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ws4py/websocket.py", line 300, in once
    b = self.sock.recv(self.reading_buffer_size)
error: [Errno 54] Connection reset by peer
[2015-02-09 09:17:37,637] INFO Terminating websocket [Local => 127.0.0.1:9000 | Remote => 127.0.0.1:53427]

It didn't really catch my attention earlier, but I'm not sure why once() would be called by send()? Or is it that send() is somehow leaving things in a bad state, and once() fails when it gets polled by the manager?

Many thanks for the quick response.
Tim

@Lawouach

This comment has been minimized.

Show comment
Hide comment
@Lawouach

Lawouach Feb 9, 2015

Owner

Mmmh, I don't know what to say. This is what the threadedclient short example does (calling send from the opened() callback) and it has always worked. Oo

Owner

Lawouach commented Feb 9, 2015

Mmmh, I don't know what to say. This is what the threadedclient short example does (calling send from the opened() callback) and it has always worked. Oo

@tshead2

This comment has been minimized.

Show comment
Hide comment
@tshead2

tshead2 Feb 9, 2015

I hadn't noticed this example because I've been (perhaps overly) focused on the server side, but I'll give it a try.

Cheers,
Tim

tshead2 commented Feb 9, 2015

I hadn't noticed this example because I've been (perhaps overly) focused on the server side, but I'll give it a try.

Cheers,
Tim

@Lawouach

This comment has been minimized.

Show comment
Hide comment
@Lawouach

Lawouach Feb 9, 2015

Owner

Thanks. I'm honestly lost here, I don't see why this would fail. It seems your client closes its socket as soon as it's opened.

Owner

Lawouach commented Feb 9, 2015

Thanks. I'm honestly lost here, I don't see why this would fail. It seems your client closes its socket as soon as it's opened.

@avishorp

This comment has been minimized.

Show comment
Hide comment
@avishorp

avishorp Jul 13, 2015

Just ran into the issue myself, similar setup (CherryPy + ws4py).

This is my WebSocket class:

 class XXWebSocket(WebSocket):
    def opened(self):
        cherrypy.log("VBWebSocket opened")
        self.send(TextMessage('blah blah '), False)

The sample you mentioned (threadedclient) is a client, not a server. Apparently, the problem is at WebSocketManager's add() function - the socket's opened() function is called before the socket gets registered, which then causes some kind of receive (probably from the browser side) to throw and exception and terminate the socket:

        logger.info("Managing websocket %s" % format_addresses(websocket))
        websocket.opened()
        with self.lock:
            fd = websocket.sock.fileno()
            self.websockets[fd] = websocket
            self.poller.register(fd)

Avishay

Just ran into the issue myself, similar setup (CherryPy + ws4py).

This is my WebSocket class:

 class XXWebSocket(WebSocket):
    def opened(self):
        cherrypy.log("VBWebSocket opened")
        self.send(TextMessage('blah blah '), False)

The sample you mentioned (threadedclient) is a client, not a server. Apparently, the problem is at WebSocketManager's add() function - the socket's opened() function is called before the socket gets registered, which then causes some kind of receive (probably from the browser side) to throw and exception and terminate the socket:

        logger.info("Managing websocket %s" % format_addresses(websocket))
        websocket.opened()
        with self.lock:
            fd = websocket.sock.fileno()
            self.websockets[fd] = websocket
            self.poller.register(fd)

Avishay

@Ficik

This comment has been minimized.

Show comment
Hide comment
@Ficik

Ficik Aug 10, 2015

I have this problem too. Client throws because websocket data from opened are sent before headers resulting in malformed HTTP header:

$ curl http://localhost:9000/ws --header "Upgrade: websocket" --header "Connection: Upgrade" --header "Sec-WebSocket-Version: 13" --header "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="
�HelloHTTP/1.1 101 Switching Protocols
Upgrade: websocket
Server: CherryPy/3.8.0
Connection: Upgrade
Date: Mon, 10 Aug 2015 12:01:08 GMT
Content-Type: text/plain;charset=utf-8
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Version: 13

Ficik commented Aug 10, 2015

I have this problem too. Client throws because websocket data from opened are sent before headers resulting in malformed HTTP header:

$ curl http://localhost:9000/ws --header "Upgrade: websocket" --header "Connection: Upgrade" --header "Sec-WebSocket-Version: 13" --header "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="
�HelloHTTP/1.1 101 Switching Protocols
Upgrade: websocket
Server: CherryPy/3.8.0
Connection: Upgrade
Date: Mon, 10 Aug 2015 12:01:08 GMT
Content-Type: text/plain;charset=utf-8
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Version: 13
@ronin8600

This comment has been minimized.

Show comment
Hide comment
@ronin8600

ronin8600 Jan 29, 2016

Is there an update on this? I'm having the same problem

Is there an update on this? I'm having the same problem

@ronin8600

This comment has been minimized.

Show comment
Hide comment
@ronin8600

ronin8600 Jan 29, 2016

I started investigating and the problem appears to be with "on_end_request " hook provided by cherrypy. The documentation states that it is called when the conversation is over and all data has been written to the client, but this doesn't appear to be true since it's getting called before the response is being sent to the client.

I started investigating and the problem appears to be with "on_end_request " hook provided by cherrypy. The documentation states that it is called when the conversation is over and all data has been written to the client, but this doesn't appear to be true since it's getting called before the response is being sent to the client.

@ronin8600

This comment has been minimized.

Show comment
Hide comment
@ronin8600

ronin8600 Jan 29, 2016

I came up with a temporary workaround by having the WSGIGateway delay closing the response until it sends the headers. This seemed to fix the issue, I'll talk with the cherrypy team about a proper fix.

I came up with a temporary workaround by having the WSGIGateway delay closing the response until it sends the headers. This seemed to fix the issue, I'll talk with the cherrypy team about a proper fix.

@moigagoo

This comment has been minimized.

Show comment
Hide comment
@moigagoo

moigagoo Mar 18, 2016

Hi!

I too can't send messages from the server on connection opening, but I'm having a slightly different error, so I thought I should share:

Traceback (most recent call last):
  File "client.py", line 10, in <module>
    ws.connect()
  File "/Users/kmolchanov/.virtualenvs/sloth/lib/python3.5/site-packages/ws4py/client/__init__.py", line 231, in connect
    self.process_response_line(response_line)
  File "/Users/kmolchanov/.virtualenvs/sloth/lib/python3.5/site-packages/ws4py/client/__init__.py", line 284, in process_response_line
    raise HandshakeError("Invalid response status: %s %s" % (code, status))
ws4py.exc.HandshakeError: Invalid response status: b'from' b'serverHTTP/1.1 101 Switching Protocols'

Here's my server class:

class MyWebSocket(WebSocket):
    def opened(self):
        self.send(b'Hello from server')

Hi!

I too can't send messages from the server on connection opening, but I'm having a slightly different error, so I thought I should share:

Traceback (most recent call last):
  File "client.py", line 10, in <module>
    ws.connect()
  File "/Users/kmolchanov/.virtualenvs/sloth/lib/python3.5/site-packages/ws4py/client/__init__.py", line 231, in connect
    self.process_response_line(response_line)
  File "/Users/kmolchanov/.virtualenvs/sloth/lib/python3.5/site-packages/ws4py/client/__init__.py", line 284, in process_response_line
    raise HandshakeError("Invalid response status: %s %s" % (code, status))
ws4py.exc.HandshakeError: Invalid response status: b'from' b'serverHTTP/1.1 101 Switching Protocols'

Here's my server class:

class MyWebSocket(WebSocket):
    def opened(self):
        self.send(b'Hello from server')
@moigagoo

This comment has been minimized.

Show comment
Hide comment
@moigagoo

moigagoo Mar 18, 2016

@ronin8600

I'll talk with the cherrypy team about a proper fix.

Any news?

@ronin8600

I'll talk with the cherrypy team about a proper fix.

Any news?

@ronin8600

This comment has been minimized.

Show comment
Hide comment
@ronin8600

ronin8600 Mar 18, 2016

@moigagoo

Your error looks to be the same issue I encountered.

I submitted a bug and proposed fix last month, but the Cherrypy team hasn't responded to either.

You can use my proposed fix below to resolve your issue

https://bitbucket.org/cherrypy/cherrypy/pull-requests/121/fixing-issue-1404-on_end_request-hook-is/diff

@moigagoo

Your error looks to be the same issue I encountered.

I submitted a bug and proposed fix last month, but the Cherrypy team hasn't responded to either.

You can use my proposed fix below to resolve your issue

https://bitbucket.org/cherrypy/cherrypy/pull-requests/121/fixing-issue-1404-on_end_request-hook-is/diff

@moigagoo

This comment has been minimized.

Show comment
Hide comment
@moigagoo

moigagoo Mar 18, 2016

@Lawouach could you please bump @ronin8600's patch to CherryPy? I've tried it, it's working.

This issue is a nasty one, really ruins the whole websocket thing for me.

@Lawouach could you please bump @ronin8600's patch to CherryPy? I've tried it, it's working.

This issue is a nasty one, really ruins the whole websocket thing for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment