python websocket handshake (RFC 6455) - javascript

I am trying to implement a simple websoket server on python, using RFC 6455 protocol.
I took handshake format from here and here.
I am using Chromium 17 and Firefox 11 as clients, and getting this error:
Uncaught Error: INVALID_STATE_ERR: DOM Exception 11
I expect to see hello from server in my browser and hello from client in server log.
I guess my handshake is wrong, can you point me to my mistake?
##Server log, request:
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 127.0.0.1:8999
Origin: null
Sec-WebSocket-Key: 8rYWWxsBPEigeGKDRNOndg==
Sec-WebSocket-Version: 13
##Server log, response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 3aDXXmPbE5e9i08zb9mygfPlCVw=
##Raw-string response:
HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: 3aDXXmPbE5e9i08zb9mygfPlCVw=\r\n\r\n
##Server code:
import socket
import re
from base64 import b64encode
from hashlib import sha1
websocket_answer = (
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: {key}\r\n\r\n',
)
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 8999))
s.listen(1)
client, address = s.accept()
text = client.recv(1024)
print text
key = (re.search('Sec-WebSocket-Key:\s+(.*?)[\n\r]+', text)
.groups()[0]
.strip())
response_key = b64encode(sha1(key + GUID).digest())
response = '\r\n'.join(websocket_answer).format(key=response_key)
print response
client.send(response)
print client.recv(1024)
client.send('hello from server')
##Client code:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript">
var s = new WebSocket('ws://127.0.0.1:8999');
s.onmessage = function(t){alert(t)};
s.send('hello from client');
</script>
</head>
<body>
</body>
</html>

Your server handshake code looks good.
The client code looks like it'll try to send a message before the (asynchronous) handshake completes however. You could avoid this by moving your message send into your websocket's onopen method.
Once the connection is established, the server does not send or receive messages as plain text. See the data framing section of the spec for details. (Client code can ignore this as the browser takes care of data framing for you.)

I was trying the same thing, but could never get it working. In the end i found an article Library for building WebSocket servers and clients in Python by Aymeric Augustin. The way he does it (code below) does the handshake for you automatically.
import asyncio
import websockets
async def echo(websocket, path):
async for message in websocket:
await websocket.send(message)
asyncio.get_event_loop().run_until_complete(websockets.serve(echo, 'localhost', 8765))
asyncio.get_event_loop().run_forever()

Related

How to send messages from server to client in a Python WebSockets server, AFTER initial handshake?

Here is a small websockets client and server POC.
It sends a single hard-coded message string from the (Python) server to the Javascript client page.
The question is, how to send further, ad-hoc messages? From the server to the client.
Tiny HTML client page with embedded Javascript:
<!DOCTYPE html>
<html lang="en">
<body> See console for messages </body>
<script>
# Create websocket
const socket = new WebSocket('ws://localhost:8000');
# Add listener to receive server messages
socket.addEventListener('open', function (event) {
socket.send('Connection Established');
});
# Add message to browser console
socket.addEventListener('message', function (event) {
console.log(event.data);
});
</script>
</html>
Here is the Python server code:
import asyncio
import websockets
import time
# Create handler for each connection
async def handler(websocket, path):
await websocket.send("message from websockets server")
# Start websocket server
start_server = websockets.serve(handler, "localhost", 8000)
# Start async code
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
This successfully sends a hard-coded message from server to client.
You can see the message in the browser console.
At this point the websocket is open.
The main application (not shown) now needs to send messages.
These will be dynamic messages, not hard-coded.
How can we send later, dynamic messages from the server?
After the code here runs?
I would like to put the socket into a global variable and call a send method but this is not possible because the server runs a continuous loop.
You can insert further messages into the Python server code like this:
import asyncio
import datetime
from typing import Iterator
import websockets
import random
websocket_connections = set()
sock_port = 8000
sock_url = 'localhost'
global_socket = lambda: None
async def register(websocket):
print('register event received')
websocket_connections.add(websocket) # Add this client's socket
global_socket = websocket
async def poll_log():
await asyncio.sleep(0.3) # Settle
while True:
await asyncio.sleep(0.3) # Slow things down
# Send a dynamic message to the client after random delay
r = random.randint(1, 10)
if (r == 5): # Only send 10% of the time
a_msg = "srv -> cli: " + str(random.randint(1,10000))
print("sending msg: " + a_msg)
websockets.broadcast(websocket_connections, a_msg) # Send to all connected clients
async def main():
sock_server = websockets.serve(register, sock_url, sock_port)
await asyncio.sleep(0.3) # Start up time
async with sock_server: await poll_log()
if __name__ == "__main__":
print("Websockets server starting up ...")
asyncio.run(main())
There is a very helpful example of a complete, full-duplex Websockets application here.
That example is part of the Websockets 10.4 documentation.
It's very helpful as a reference and to understand how websockets are used.

Can't decode handshake request from client

I'm trying to connect a python3 socket with a JavaScript WebSocket. I'm testing the server code on localhost:8080, and connecting with Chrome(94.0).
The WebSocket client and the socket server do establish a connection. However, the connection would be shut down if the server did not follow the protocol and respond to the handshake. According to the protocol, the client WebSocket sends a utf-8 encoded GET request to the socket server, and the server must parse that request in order to complete the handshake.
What I get from the client is this:
\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03\x97t\xb1\xf7\xac\x99\x91\xd4\xf5\n\xdf\xc3X\x8af<\xbe\x99(0\x88\x9a!\xc6\xc9\x17]\xfe\xd9sP\xcc \xa8\xcf\x90{\x8a\xfcm\xbcj-5\xdf\xf90\x81\xc8Y\xc1\x85q"\xfe!C\xbb\t\xbd}\xe0\x8d\xf1\xe5\x00 \x1a\x1a\x13\x01\x13\x02\x13\x03\xc0+\xc0/\xc0,\xc00\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00/\x005\x01\x00\x01\x93\x1a\x1a\x00\x00\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\n\x00\n\x00\x08\xfa\xfa\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00#\x00\x00\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\r\x00\x12\x00\x10\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x00\x12\x00\x00\x003\x00+\x00)\xfa\xfa\x00\x01\x00\x00\x1d\x00 \xfa)\xd5\x85<\x81.\x7f\xc0\x87wA!\xf1\xc9\xf80\xeb\x01\xdc\xed3m\xd1\x98\xd6\xd8\xd7\x7f#\rM\x00-\x00\x02\x01\x01\x00+\x00\x0b\n\x8a\x8a\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02JJ\x00\x01\x00\x00\x15\x00\xf7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
The client consistently sends these bytes, although it this does not look like a legitimate GET request. This can't be decoded by utf-8 or by other encodings including utf-16-le, utf-16-be, unicode-escape, etc.
client source:
var client = new WebSocket('wss://127.0.0.1:8080')
client.onopen = function(e) {
console.log("open");
}
client.onmessage = function(e) {
console.log(e.data)
}
server handshake handler:
def handshake(client, address):
req = client.recv(1024).decode('utf-8')
key = (re.search('Sec-WebSocket-Key:\s+(.*?)[\n\r]+', req).groups()[0].strip())
response_key = b64encode(sha1(key + sockey).digest())
response = '\r\n'.join(websock_ans).format(key=response_key)
client.send(response.encode('utf-8'))
As the client request isn't utf-8 bytes, this gives a decoding error in line 2.
following the websocket protocol (https://datatracker.ietf.org/doc/html/rfc6455), sockey and websock_ans are defined as follows:
sockey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
websock_ans = {
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: {key}\r\n\r\n',
}
Does WebSocket compress/encrypt its GET requests? As far as I checked, the documents do not state any compression/encryption algorithms.
Thanks in advance.
Use gzip to convert the bytes into objects.

java script websocket can't connect to python serveur

i want that the serveur connect and send data to the python serveur but unfortunately i have this errorSCRIPT12029: SCRIPT12029: WebSocket Error: Network Error 12029, i have seen on this website Connecting to TCP Socket from browser using javascript at the second post when he says You can use also attempt to use HTML5 Web Sockets (Although this is not direct TCP communication):
so this is the java script html code
<!DOCTYPE html>
<html>
<head>
<title>JS #0</title>
</head>
<body>
<script>
try{
var connection = new WebSocket('ws://127.0.0.1:1555');
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
}catch(Exception){
}
</script>
</body>
</html>
python
# coding: utf-8
import socket
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
a=1
if(a==1):
try:
socket.bind(('', 1555))
socket.listen(5)
print("client start")
client, address = socket.accept()
print ("{} connected".format( address ))
response = client.recv(255)
if response != "":
print(response)
except Exception as e:
print(e)
finally:
socket.close()
Second try
#!/usr/bin/env python
# WS server that sends messages at random intervals
import asyncio
import datetime
import random
import websockets
async def time(websocket, path):
while True:
now = datetime.datetime.utcnow().isoformat() + "Z"
await websocket.send(now)
await asyncio.sleep(random.random() * 3)
start_server = websockets.serve(time, "127.0.0.1", 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
and the html code
<!DOCTYPE html>
<html>
<head>
<title>WebSocket demo</title>
</head>
<body>
<script>
var ws = new WebSocket("ws://127.0.0.1:5678/"),
messages = document.createElement('ul');
ws.onmessage = function (event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode(event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
</script>
</body>
</html>
have i done wrong or it's not the right code, i have found the code on this website https://websockets.readthedocs.io/en/stable/intro.html
new photo of error with Microsoft edge.
configuration with about:flags
second post answer of the website give in the awnser
detecter automaticement le reseau intranet= automatically detect the intranet network
Not the world's best answer, but hopefully this will get you on track!
Browsers do not support raw sockets, but they do support one specific socket protocol, WebSockets. WebSockets are built on top of TCP/IP and are a great, easy way to form long-lived connections between a browser and another machine. Because your code was originally utilizing raw sockets, the browser was never going to perform a handshake. Now that you've changed your answer to support websockets, you're closer than ever!
I'm not sure what issue you're experiencing with your new code because it works perfectly for me. I made a few modifications since I am running a lot of dev environments and I can't have StackExchange debugging interfering. Here's my code which only has 3 changed lines from yours:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket demo</title>
</head>
<body>
<script>
var ws = new WebSocket('ws://127.0.0.1:5678/'),
messages = document.createElement('ul');
ws.onmessage = function(event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode(event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
</script>
</body>
</html>
#!/usr/bin/env python3
# WS server example
import sys
# forcibly adding a path for the following libraries
# this is probably not necessary on anyone else's machine,
# but I need it just for testing this answer
sys.path.append('/usr/local/lib/python3.7/site-packages')
import asyncio
import websockets
import datetime
import random
async def time(websocket, path):
while True:
now = datetime.datetime.utcnow().isoformat() + "Z"
await websocket.send(now)
await asyncio.sleep(random.random() * 3)
start_server = websockets.serve(time, "127.0.0.1", 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
And it works great:
I saved your python script as foo.py and the html document as bar.html to my desktop. To start the python server, I ran python3 foo.py from the command line, and then I opened the html file using my preferred browser, no http servers were required for this example.
What errors are you seeing in the browser or console that are prohibiting this from working?
Error 12029 is the error OP is seeing! By default, Edge will not listen on local interfaces, e.g. localhost and 127.0.0.1. This thread on Microsoft.com has some troubleshooting advice for developers using Edge. Let us know if these configurations are helpful.

Handshake error with WebSocket python server and JS client

I am trying to setup a communication between a python script (that will do a lot of computation on data that cannot be done in javascript and send send that data as a json) and a javascript client.
I have the following code for my python server:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 9888 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'OK...' + data
if not data:
break
conn.sendall(reply)
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
s.close()
And the following code for my javascript client:
var connection = new WebSocket('ws://127.0.0.1:8999');
connection.onopen = function () {
connection.send('Hello'); // Send the message to the server
};
I get the following error from my javascript client:
Error during WebSocket handshake: net::ERR_INVALID_HTTP_RESPONSE
And the following output from my python server
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:53956
Unhandled exception in thread started by <function clientthread at 0x10abac578>
Traceback (most recent call last):
File "server.py", line 71, in clientthread
data = conn.recv(1024)
socket.error: [Errno 54] Connection reset by peer
Would anyone know what is wrong?
Edit: forgot to mention that I have seen this SO Post before, but my problem is not the same, or rather should I say that the error encountered by OP is not the same as mine.
A WebSocket is a not the same as a plain TCP socket you create. WebSocket is a protocol on top of TCP instead which starts with a HTTP handshake and then continues with a framing based protocol. If you want to implement a WebSocket server in Python you need to implement this protocol as specified in RFC 6455 or use existing WebSocket libraries.
An example server-side python code using WebSocket is:
import asyncio
import websockets
async def handle_message(message):
print(message)
async def consumer_handler(websocket, path):
while True:
message = await websocket.recv()
await handle_message(message)
start_server = websockets.serve(consumer_handler, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

How do I use web sockets in javascript/html5 to communicate with python

I'm having issue's with trying to communicate between python and javascript using WebSockets.
This is my python server (ws.py) which just prints out any data it receives and resends it to the client :
#!/usr/bin/env python
# Echo server program
import socket
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
print 'Data recieved =', data
conn.sendall(data)
conn.close()
This works fine with netcat using nc localhost 50007 but when I try using my html/Javascript client I get a connection but the server doesn't receive the message I just get the follow:
Connected by ('127.0.0.1', 62264)
Data recieved = GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:50007
Origin: http://localhost
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: 6hxDWShxMnFxwGYAWym+eg==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36
Cookie: SQLiteManager_currentLangue=2
and this is what I get the the console in Chrome:
WebSocket connection to 'ws://localhost:50007/' failed: basicWSoc.html:7
Error Logged: [object Event]
This is my web client (basicWSoc.html)
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function WebSocketTest()
{
var connection=new WebSocket("ws://localhost:50007");
connection.onopen = function () {
connection.send('Hello, Server!!'); //send a message to server once connection is opened.
};
connection.onerror = function (error) {
console.log('Error Logged: ' + error); //log errors
};
connection.onmessage = function (e) {
console.log('Received From Server: ' + e.data); //log the received message
};
}
</script>
</head>
<body>
<div id="sse">
Run WebSocket
</div>
</body>
</html>
Now I am still a novice in python and Web sockets are completely new to me so I may be over looking the obvious....
Any Help would be greatly appreciated
Thanks to #SLaks who pointed out to me that I was using TCP sockets as apposed to Web Sockets. I changed my Python service to use the Tornado Library which implemented web sockets and this allowed me to connect to my web client and successfully communicate between them

Categories

Resources