I'm trying to implement a REST client in python that reacts to messages received from the server received through an opened websocket with the concerned server.
Here is the scenario:
client opens a websocket with the server
from time to time, the server sends a message to the client
when the client receives the messages, it gets some information from
the server
The current client I have is able to open the websocket and to receive the message from the server. However, as soon as it receives the messages, it gets the information from the server then terminates while I'd like to keep it listening for other messages that will make it get a new content from the server.
Here is the piece of code I have:
def openWs(serverIp, serverPort):
##ws url setting
wsUrl = "ws://"+serverIp+":"+serverPort+"/websocket"
##open ws
ws = create_connection(wsUrl)
##send user id
print "Sending User ID..."
ws.send("user_1")
print "Sent"
##receiving data on ws
print "Receiving..."
result = ws.recv()
##getting new content
getUrl = "http://"+serverIp+":"+serverPort+"/"+result+"/entries"
getRest(getUrl)
I don't know if using threads is appropriate or not, I'm not expert in that.
If someone could help, it'll be great.
Thanks in advance.
I finished with this code, doing what I'm expecting. Git it from here
import websocket
import thread
import time
def on_message(ws, message):
print message
def on_error(ws, error):
print error
def on_close(ws):
print "### closed ###"
def on_open(ws):
def run(*args):
for i in range(3):
time.sleep(1)
ws.send("Hello %d" % i)
time.sleep(1)
ws.close()
print "thread terminating..."
thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://localhost:5000/chat",
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
Related
I am working on a websocket application that utilizes WebSocketApp from websocket-client. As my websocket is running, and listening for messages I would like to be able to call a method to send a message to the server as needed.
WebSocket
import websocket
class WebSocketTest():
wsapp = None
print("starting websocket app")
ws_is_open = False
def on_message(self, wsapp, message):
print("ON_MESSAGE")
print(message)
def on_open(self, wsapp):
print("SOCKET OPENING")
self.ws_is_open = True
def on_close(self):
print("SOCKET CLOSING")
async def start(self):
self.wsapp = websocket.WebSocketApp("ws://localhost:5001",
on_message=self.on_message,
on_close=self.on_close,
on_open=self.on_open)
self.wsapp.run_forever()
def send(self, msg):
if self.ws_is_open:
print(f"SENDING: {msg}")
self.wsapp.send(msg)
Test Setup File
from websocketapp import WebSocketTest
import asyncio
ws = WebSocketTest()
asyncio.run(ws.start())
ws.send("Hello!")
Output
some_user python % python test.py
starting websocket app
SOCKET OPENING
I have created a setup file that initializes the class, starts the server and then attempts to send a message using the send method. It looks like it never gets to the line that calls send. The connection to the server works, and if I broadcast a message from my websocket server to the client on_message is triggered and I see the message printed out.
I am attempting to setup a websocket using the websocket-client library using python 3.7. The documentation from the API provider states that basic auth is required.
Below is the code I am using to try subscribing to their test channel. The test channel should send responses back nonstop until we close the socket.
email = b'myemail#domain.com'
pw = b'mypassword'
_str = (base64.b64encode(email + b':' + pw)).decode('ascii')
headerValue = 'Authorization: Basic {0}'.format(_str)
def on_message(ws, msg):
global msg_received
print("Message received: ", msg)
msg_received += 1
if msg_received > 10:
ws.send(json.dumps({"unsubscribe": "/test"}))
ws.close()
def on_error(ws, error):
print("ERROR: ", error)
def on_close(ws):
print("Closing websocket...")
def on_open(ws):
print("Opening...")
ws.send(json.dumps({'subscribe': '/test'}))
time.sleep(1)
if __name__ == '__main__':
websocket.enableTrace(True)
ws = websocket.WebSocketApp("wss://api-ws.myurl.com/",
header=[headerValue],
on_message=on_message,
on_error=on_error,
on_close=on_close))
ws.on_open = on_open
ws.run_forever()
When I run this, I am able to see my request headers, and their response headers which show that the connection was upgraded to a websocket and I am assigned a Sec-Websocket-Accept. Then, the websocket immediately closes without any responses coming through.
I have tried first sending a post request to the login api and generating a sessionID and csrftoken, and then passing those as cookies in the websocketapp object. It didn't work. I have tried passing the headers as an actual dict but that doesn't work either. I've tried way too many variations of the b64 encoding and none of them work.
Any advice would be appreciated.
all.
In my project,I built two websocket connections. one is used for sending pictures from server to client, and the other is used for sending some control data from client to server. now I use only one client.
var ws2 = new WebSocket('ws://xx.xx.xx.xx:9002/control')
var ws1 = new WebSocket('ws://xx.xx.xx.xx:9002/data')
ws.binaryType = 'blob'
ws2.onopen =()=> console.log('ws2 connected.')
On the server side, once ws1 is open, it constently send data to the client. q is a global queue from which I get the data. This part works fine.
The problem is that the program can not run into on_message(self, message) in function in ws2 after I send message from the client side.
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
class myWebSocket(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True;
def open(self):
print "websocket1 open."
while self.ws_connection is not None:
print "send..."
try:
self.write_message(q.get(),True)
except tornado.websocket.WebSocketClosedError:
self.close()
def on_message(self, message):
print("websocket1 received message.")
print message
def on_close(self):
print("websocket1 closed.")
class controlWebSocket(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True;
def open(self):
print "websocket2 open"
def on_message(self, message):
print("websocket2 received message.")
print message
def on_close(self):
print("websocket2 closed.")
and I am sure the client successfully send the control data by click a button.
<script>
function test(){
ws2.send("this is from ws2.")
alert("home clicked.")
}
</script>
and I also found that once the open function in ws1 stopped, the ws2 can receive the message. I don't understand why ws1 sending data caused ws2 unable to receive data.
I'm new in python programming and tornado websocket. anyone can help on this problem, thanks a lot~!
Tornado is built on non-blocking concurrency. This means you must generally avoid blocking methods (or run them in a thread pool). q.get() is a blocking method, so nothing else in Tornado can run while it is waiting for a message. You should probably replace this queue with a tornado.queues.Queue.
I have my Tornado client continuously listening to my Tornado server in a loop, as it is mentioned here - http://tornadoweb.org/en/stable/websocket.html#client-side-support. It looks like this:
import tornado.websocket
from tornado import gen
#gen.coroutine
def test():
client = yield tornado.websocket.websocket_connect("ws://localhost:9999/ws")
client.write_message("Hello")
while True:
msg = yield client.read_message()
if msg is None:
break
print msg
client.close()
if __name__ == "__main__":
tornado.ioloop.IOLoop.instance().run_sync(test)
I'm not able to get multiple instances of clients to connect to the server. The second client always waits for the first client process to end before it connects to the server. The server is set up as follows, with reference from Websockets with Tornado: Get access from the "outside" to send messages to clients and Tornado - Listen to multiple clients simultaneously over websockets.
class WSHandler(tornado.websocket.WebSocketHandler):
clients = set()
def open(self):
print 'new connection'
WSHandler.clients.add(self)
def on_message(self, message):
print 'message received %s' % message
# process received message
# pass it to a thread which updates a variable
while True:
output = updated_variable
self.write_message(output)
def on_close(self):
print 'connection closed'
WSHandler.clients.remove(self)
application = tornado.web.Application([(r'/ws', WSHandler),])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(9999)
tornado.ioloop.IOLoop.instance().start()
But this has not worked - for some reason even after I have made a successful first connection, the second connection just fails to connect i.e. it does not even get added to the clients set.
I initially thought the while True would not block the server from receiving and handling more clients, but it does as without it multiple clients are able to connect. How can I send back continuously updated information from my internal thread without using the while True?
Any help would be greatly appreciated!
To write messages to client in a while loop, you can use the yield None inside the loop. This will pause the while loop and then Tornado's IOLoop will be free to accept new connections.
Here's an example:
#gen.coroutine
def on_message(self):
while True:
self.write_message("Hello")
yield None
Thanks for your answer #xyres! I was able to get it to work by starting a thread in the on_message method that handed processing and the while True to a function outside the WSHandler class. I believe this allowed for the method to run outside of Tornado's IOLoop, unblocking new connections.
This is how my server looks now:
def on_message(self, message):
print 'message received %s' % message
sendThread = threading.Thread(target=send, args=(self, message))
sendThread.start()
def send(client, msg):
# process received msg
# pass it to a thread which updates a variable
while True:
output = updated_variable
client.write_message(output)
Where send is a function defined outside the class which does the required computation for me and writes back to client inside thewhile True.
I'm trying to use websockets in python, and i previously asked a question about this. I quickly realized, though, that the way i was connecting to the server was meant for "one off" messages, while what i want to do needs to listen for notifications constantly.
In the documentation for the python websocket client i can see the following code:
import websocket
import thread
import time
def on_message(ws, message):
print message
def on_error(ws, error):
print error
def on_close(ws):
print "### closed ###"
def on_open(ws):
def run(*args):
for i in range(3):
time.sleep(1)
ws.send("Hello %d" % i)
time.sleep(1)
ws.close()
print "thread terminating..."
thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://echo.websocket.org/",
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
The thing is, i'm still quite new to python, and i don't completely understand this code. Since it's example code, and does things that i don't need it to, i would like to understand how it works. I, for example, don't understand what the for loop is needed for, or what the __name__ and the __main__ at the bottom are.
Is there a better way?
Thanks,
Sas :)
The for loop is probably just an example since it will just print Hello 0, Hello 1 and Hello 2.
__name__ == "__main__" is true when the Python interpreter is running a module as the main program, which you can read more about here. Whenever that happens, it assigns what functions should be used on message, error and when the socket closes. And when that's done it runs the WebSocket forever.
So, to create your own long-lived WebSocket you can copy this example code and change the on_message, on_error, on_close and on_open functions to do what you want them to do whenever these events occour. on_message activates whenever a message is sent, on_error when an error occours, on_close when the WebSocket closes and on_open when the WebSocket opens.