Python websocket-client 연결 에러
Diagnosing and fixing Python websocket-client connection errors — handshake failures, SSL issues, timeout handling, and reconnection strategies.
Python websocket-client 연결 에러
Introduction
WebSockets provide persistent, bidirectional communication between clients and servers. They are essential for real-time applications like chat systems, live dashboards, and trading platforms. However, websocket connections are more fragile than HTTP connections, and the error messages are often less informative.
I built a real-time cryptocurrency price monitor using websockets in Lisbon. The connection would drop frequently due to network issues, and the default websocket-client behavior was to crash instead of reconnecting gracefully.
Environment
Python 3.12.3
websocket-client 1.7.1Problem
Error 1: Handshake failure
import websocket
ws = websocket.create_connection("ws://localhost:8765")websocket.WebSocketBadStatusException: Handshake status 403 ForbiddenError 2: Connection refused
import websocket
ws = websocket.create_connection("ws://localhost:8765")ConnectionRefusedError: [Errno 111] Connection refusedError 3: SSL certificate error
import websocket
ws = websocket.create_connection("wss://api.example.com/ws")ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: self-signed certificate (_ssl.c:1006)Error 4: Connection drops silently
import websocket
import time
def on_message(ws, message):
print(f"Received: {message}")
ws = websocket.WebSocketApp(
"wss://api.example.com/ws",
on_message=on_message
)
ws.run_forever()
# Connection drops after some time — no automatic reconnectionAnalysis
WebSocket errors fall into several categories.
Handshake errors (4xx/5xx): The initial HTTP upgrade request failed. This can be due to wrong URL, missing headers, authentication failure, or server-side rejection.
Connection errors: The TCP connection itself failed. Server is not running, wrong port, or firewall blocking.
SSL errors: Certificate verification failed. Common with self-signed certificates or corporate proxies.
Timeout errors: The server did not respond to the handshake within the timeout period.
Disconnection errors: The established connection was closed by the server or network.
Check connection status:
import websocket
ws = websocket.create_connection("wss://api.example.com/ws")
print(f"Connected: {ws.connected}")
print(f"Socket: {ws.sock}")Solution
Fix 1: Handle handshake with proper headers
import websocket
headers = {
"Authorization": "Bearer your-token",
"User-Agent": "MyApp/1.0",
}
ws = websocket.create_connection(
"wss://api.example.com/ws",
header=headers,
timeout=10
)Fix 2: Disable SSL verification for development
import websocket
import ssl
# Development only — never use in production
ws = websocket.create_connection(
"wss://localhost:8765",
sslopt={"cert_reqs": ssl.CERT_NONE}
)
# Production — provide CA bundle
ws = websocket.create_connection(
"wss://api.example.com/ws",
sslopt={"ca_certs": "/path/to/ca-bundle.crt"}
)Fix 3: Auto-reconnection with WebSocketApp
import websocket
import time
import threading
class ReconnectingWebSocket:
def __init__(self, url, on_message=None, on_error=None):
self.url = url
self.on_message = on_message or self._default_on_message
self.on_error = on_error or self._default_on_error
self.ws = None
self.should_reconnect = True
self.reconnect_delay = 1
self.max_delay = 60
def _default_on_message(self, ws, message):
print(f"Received: {message}")
def _default_on_error(self, ws, error):
print(f"Error: {error}")
def _on_close(self, ws, close_status_code, close_msg):
print(f"Connection closed: {close_status_code} {close_msg}")
if self.should_reconnect:
self._reconnect()
def _on_open(self, ws):
print("Connection opened")
self.reconnect_delay = 1 # Reset delay on successful connection
def _reconnect(self):
if not self.should_reconnect:
return
print(f"Reconnecting in {self.reconnect_delay}s...")
time.sleep(self.reconnect_delay)
# Exponential backoff
self.reconnect_delay = min(self.reconnect_delay * 2, self.max_delay)
self.connect()
def connect(self):
self.ws = websocket.WebSocketApp(
self.url,
on_message=self.on_message,
on_error=self.on_error,
on_close=self._on_close,
on_open=self._on_open
)
self.ws.run_forever()
def close(self):
self.should_reconnect = False
if self.ws:
self.ws.close()
# Usage
client = ReconnectingWebSocket("wss://api.example.com/ws")
client.connect() # Blocks and reconnects on failureFix 4: Threaded WebSocket with ping/pong
import websocket
import threading
import time
class ThreadedWebSocket:
def __init__(self, url):
self.url = url
self.ws = None
self.thread = None
self.running = False
def start(self):
self.running = True
self.thread = threading.Thread(target=self._run, daemon=True)
self.thread.start()
def _run(self):
while self.running:
try:
self.ws = websocket.WebSocketApp(
self.url,
on_message=self._on_message,
on_error=self._on_error,
on_close=self._on_close
)
self.ws.run_forever(
ping_interval=30, # Send ping every 30s
ping_timeout=10 # Wait 10s for pong
)
except Exception as e:
print(f"Connection error: {e}")
if self.running:
time.sleep(5) # Wait before reconnecting
def _on_message(self, ws, message):
print(f"Received: {message}")
def _on_error(self, ws, error):
print(f"Error: {error}")
def _on_close(self, ws, status_code, msg):
print(f"Closed: {status_code}")
def stop(self):
self.running = False
if self.ws:
self.ws.close()
# Usage
client = ThreadedWebSocket("wss://api.example.com/ws")
client.start()
# ... do other work ...
client.stop()Fix 5: Ping/pong keep-alive
import websocket
import time
def on_open(ws):
def keep_alive():
while ws.keep_running:
ws.send("ping")
time.sleep(30)
thread = threading.Thread(target=keep_alive, daemon=True)
thread.start()
ws = websocket.WebSocketApp(
"wss://api.example.com/ws",
on_open=on_open,
on_message=lambda ws, msg: print(f"Received: {msg}")
)
ws.run_forever()Lessons Learned
- Always implement reconnection logic — WebSocket connections are inherently less stable than HTTP.
- Use exponential backoff for reconnection attempts to avoid overwhelming the server.
- Enable ping/pong keep-alive to detect dead connections early.
- Run WebSocket operations in a separate thread if your application needs to do other work.
- Handle SSL properly — never disable certificate verification in production.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.