|
2 | 2 | import ssl |
3 | 3 | import ubinascii |
4 | 4 | from websocket import websocket |
| 5 | +import time |
5 | 6 |
|
6 | 7 | # Connect to Wi-Fi (disabled as per your code) |
7 | 8 | if False: |
|
13 | 14 | print('Connected:', wlan.ifconfig()) |
14 | 15 |
|
15 | 16 | # Resolve hostname |
| 17 | +# Option 1: echo.websocket.events (unreliable) |
16 | 18 | host = 'echo.websocket.events' |
17 | 19 | port = 443 |
| 20 | +handshake_path = '/' |
| 21 | +# Option 2: ws.postman-echo.com (recommended for testing) |
| 22 | +# host = 'ws.postman-echo.com' |
| 23 | +# port = 443 |
| 24 | +# handshake_path = '/raw' |
| 25 | + |
18 | 26 | try: |
19 | 27 | addr_info = socket.getaddrinfo(host, port)[0][-1] |
20 | 28 | print('Resolved address:', addr_info) |
|
41 | 49 | sock.close() |
42 | 50 | raise |
43 | 51 |
|
| 52 | +# Set socket to non-blocking |
| 53 | +ssl_sock.setblocking(False) |
| 54 | +print('Socket set to non-blocking') |
| 55 | + |
44 | 56 | # Perform WebSocket handshake |
45 | 57 | key = ubinascii.b2a_base64(b'random_bytes_here').strip() |
46 | 58 | handshake = ( |
47 | | - 'GET / HTTP/1.1\r\n' |
| 59 | + 'GET {} HTTP/1.1\r\n' |
48 | 60 | 'Host: {}\r\n' |
49 | 61 | 'Upgrade: websocket\r\n' |
50 | 62 | 'Connection: Upgrade\r\n' |
51 | 63 | 'Sec-WebSocket-Key: {}\r\n' |
52 | 64 | 'Sec-WebSocket-Version: 13\r\n' |
53 | 65 | '\r\n' |
54 | | -).format(host, key.decode()) |
| 66 | +).format(handshake_path, host, key.decode()) |
55 | 67 |
|
56 | 68 | # Send handshake request |
57 | 69 | try: |
|
63 | 75 | ssl_sock.close() |
64 | 76 | raise |
65 | 77 |
|
66 | | -# Read HTTP response until \r\n\r\n |
| 78 | +# Read HTTP response until \r\n\r\n (minimize reading) |
67 | 79 | response_bytes = bytearray() |
68 | | -max_read = 1024 # Maximum bytes to read |
69 | | -read_timeout = 2 # Reduced timeout (seconds) |
70 | | -import time |
71 | | - |
| 80 | +max_read = 1024 |
| 81 | +read_timeout = 2 |
72 | 82 | start_time = time.time() |
73 | 83 | while len(response_bytes) < max_read: |
74 | 84 | try: |
|
79 | 89 | print('Received chunk, length:', len(chunk), 'bytes:', chunk) |
80 | 90 | response_bytes.extend(chunk) |
81 | 91 | print('Total bytes received:', len(response_bytes)) |
82 | | - # Check for end of HTTP headers (\r\n\r\n) |
83 | 92 | if b'\r\n\r\n' in response_bytes: |
84 | 93 | print('End of HTTP headers detected') |
| 94 | + # Decode and verify HTTP response immediately |
| 95 | + http_end = response_bytes.find(b'\r\n\r\n') + 4 |
| 96 | + if http_end < 4: |
| 97 | + ssl_sock.close() |
| 98 | + raise Exception('Invalid HTTP response: no headers found') |
| 99 | + http_response_bytes = response_bytes[:http_end] |
| 100 | + try: |
| 101 | + response = http_response_bytes.decode('utf-8') |
| 102 | + print('Decoded HTTP response:', response) |
| 103 | + except UnicodeError as e: |
| 104 | + print('UnicodeError during decode:', e) |
| 105 | + printable = ''.join(c if 32 <= ord(c) < 127 else '.' for c in http_response_bytes.decode('latin-1')) |
| 106 | + print('Printable characters:', printable) |
| 107 | + ssl_sock.close() |
| 108 | + raise Exception('Failed to decode HTTP response') |
| 109 | + if '101 Switching Protocols' not in response: |
| 110 | + print('Handshake response:', response) |
| 111 | + ssl_sock.close() |
| 112 | + raise Exception('Handshake failed') |
| 113 | + # Stop reading to leave WebSocket frame in socket buffer |
| 114 | + print('Stopping read to preserve WebSocket frame') |
85 | 115 | break |
86 | 116 | except Exception as e: |
87 | 117 | print('Error reading chunk:', e) |
|
90 | 120 | print('Read timeout reached') |
91 | 121 | break |
92 | 122 |
|
93 | | -# Inspect raw bytes |
94 | | -print('Raw response bytes:', response_bytes) |
95 | | -print('Raw response hex:', response_bytes.hex()) |
96 | | - |
97 | | -# Split HTTP response from any subsequent data |
98 | | -http_end = response_bytes.find(b'\r\n\r\n') + 4 |
99 | | -if http_end < 4: |
100 | | - ssl_sock.close() |
101 | | - raise Exception('Invalid HTTP response: no headers found') |
102 | | -http_response_bytes = response_bytes[:http_end] |
103 | | -extra_bytes = response_bytes[http_end:] if http_end < len(response_bytes) else b'' |
104 | | -print('HTTP response bytes:', http_response_bytes) |
105 | | -print('Extra bytes (if any):', extra_bytes) |
106 | | - |
107 | | -# Decode HTTP response |
| 123 | +# Create WebSocket object |
108 | 124 | try: |
109 | | - response = http_response_bytes.decode('utf-8') |
110 | | - print('Decoded HTTP response:', response) |
111 | | -except UnicodeError as e: |
112 | | - print('UnicodeError during decode:', e) |
113 | | - # Dump printable characters as fallback |
114 | | - printable = ''.join(c if 32 <= ord(c) < 127 else '.' for c in http_response_bytes.decode('latin-1')) |
115 | | - print('Printable characters:', printable) |
116 | | - ssl_sock.close() |
117 | | - raise Exception('Failed to decode HTTP response') |
118 | | - |
119 | | -# Check for valid WebSocket handshake |
120 | | -if '101 Switching Protocols' not in response: |
121 | | - print('Handshake response:', response) |
| 125 | + ws = websocket(ssl_sock, True) |
| 126 | + print('WebSocket object created') |
| 127 | +except Exception as e: |
| 128 | + print('Failed to create WebSocket object:', e) |
122 | 129 | ssl_sock.close() |
123 | | - raise Exception('Handshake failed') |
124 | | - |
125 | | -# Push back extra bytes (WebSocket frame) to the socket |
126 | | -if extra_bytes: |
127 | | - print('Note: Extra bytes detected, will be handled by websocket module') |
| 130 | + raise |
128 | 131 |
|
129 | | -# Create WebSocket object |
130 | | -ws = websocket(ssl_sock, True) |
| 132 | +# Send and receive data with retries |
| 133 | +try: |
| 134 | + bytes_written = ws.write('Hello, Secure WebSocket!') |
| 135 | + print('Sent message, bytes written:', bytes_written) |
| 136 | +except Exception as e: |
| 137 | + print('Failed to send message:', e) |
| 138 | + ws.close() |
| 139 | + raise |
131 | 140 |
|
132 | | -# Send and receive data |
133 | | -ws.write('Hello, Secure WebSocket!') |
134 | | -for _ in range(50): |
135 | | - data = ws.read(1024) |
136 | | - print('Received:', data) |
137 | | - time.sleep_ms(100) |
| 141 | +# Try reading multiple times to catch initial message or echo |
| 142 | +max_attempts = 5 |
| 143 | +read_timeout = 1 # Short timeout per read |
| 144 | +for attempt in range(max_attempts): |
| 145 | + try: |
| 146 | + data = ws.read(1024) |
| 147 | + print('Read attempt', attempt + 1, 'received:', data) |
| 148 | + if data: |
| 149 | + break |
| 150 | + time.sleep(0.5) # Wait briefly before retrying |
| 151 | + except Exception as e: |
| 152 | + print('Read attempt', attempt + 1, 'error:', e) |
| 153 | + time.sleep(0.5) |
| 154 | + if time.time() - start_time > read_timeout: |
| 155 | + print('Read timeout reached') |
| 156 | + break |
138 | 157 |
|
139 | 158 | # Close connection |
140 | 159 | ws.close() |
| 160 | +print('Connection closed') |
0 commit comments