Python websocket-client reconnect after server restart

Question:

I want to implement a client-server application with Python(client) and Spring Boot(Server) over websockets. I want client to try to connect server even if it is stopped, has network problems etc.

import time
from threading import Thread, Event

import rel
import stomper
import websocket
import logging

class ClientSocket:
 def __init__(self):
    self.opened = None
    self.thread = None
    self.opened = False
    self.try_connecting = Event()
    self.ws = websocket.WebSocketApp("ws://localhost:8080/socket",
                                     header={
                                         'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9.ey'},
                                     on_open=self.on_open,
                                     on_message=self.on_message,
                                     on_error=self.on_error,
                                     on_close=self.on_close)
    # self.rel = rel
    self.ws.run_forever(dispatcher=rel)
    rel.signal(2, rel.abort)  # Keyboard Interrupt
    rel.dispatch()

def on_message(self, ws, message):
    print(message)

def on_error(self, ws, error):
    print(error)

def on_close(self, ws, close_status_code, close_msg):
    print("### closed ###")
    if self.opened:
        self.connect_abort_server()
    if not self.try_connecting.is_set():
        self.try_connecting.set()
        self.auto_reconnect()

def on_open(self, ws):
    self.opened = True
    if self.try_connecting.is_set():
        self.try_connecting.clear()
    print("Opened connection")
    time.sleep(2)
    ws.send("CONNECTnaccept-version:1.0,1.1,2.0nnx00n")

    # Subscribing to all required desitnations.
    sub = stomper.subscribe("/user/queue/reply", "clientuniqueId", ack="auto")
    ws.send(sub)

def connect_abort_server(self):
    self.opened = False
    rel.abort()
    self.ws.close()
    self.ws = websocket.WebSocketApp("ws://localhost:8080/socket",
                                     header={
                                         'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9.ey'},
                                     on_open=self.on_open,
                                     on_message=self.on_message,
                                     on_error=self.on_error,
                                     on_close=self.on_close)

def thread_func(self):
    while self.try_connecting.is_set():
        try:
            self.ws.run_forever(dispatcher=rel)  # Set dispatcher to automatic reconnection
            # self.rel.signal(2, self.rel.abort)  # Keyboard Interrupt
            # rel.dispatch()
            time.sleep(2)
            print('Worker thread running...')
        except ConnectionResetError:
            print("==> ConnectionResetError")
            pass
    print('Worker closing down')

def auto_reconnect(self):
    self.thread = Thread(target=self.thread_func())
    self.thread.daemon = True
    time.sleep(2)
    self.thread.start()


if __name__ == "__main__":
   LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
   logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
   client_socket = ClientSocket()

In above:

  • Case 1: Server is not working and client tries to connect ✔️
  • Case 2: Server starts working and client connects ✔️
  • Case 3: Server is stopped and client tries to connect x

In the 3rd case after server closed, on_open method is invoked very oddly. Is there any solution or different way?

Thanks.

Asked By: misman

||

Answers:

After release 1.4.0 of websocket-client, the problem is fixed. You don’t even need to use thread in order to provide continuous tries for reconnecting to server.

class ClientSocket:
    def __init__(self):
        self.opened = False
        self.ws = websocket.WebSocketApp("ws://localhost:8080/socket",
                                         header={
                                             'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9'},
                                         on_open=self.on_open,
                                         on_message=self.on_message,
                                         on_error=self.on_error,
                                         on_close=self.on_close)
        self.ws.run_forever(dispatcher=rel)
        rel.signal(2, rel.abort)  # Keyboard Interrupt
        rel.dispatch()

    def on_message(self, ws, message):
        print(message)

    def on_error(self, ws, error):
        print(error)

    def on_close(self, ws, close_status_code, close_msg):
        print("### closed ###")
        rel.abort()
        self.ws.run_forever(dispatcher=rel)
        rel.signal(2, rel.abort)
        rel.dispatch()

    def on_open(self, ws):
        print("Opened connection")
        time.sleep(2)
        ws.send("CONNECTnaccept-version:1.0,1.1,2.0nnx00n")

        # Subscribing to all required desitnations.
        sub = stomper.subscribe("/user/queue/reply", "clientuniqueId", ack="auto")
        ws.send(sub)
Answered By: misman
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.