How can I create a websocket JSObject in brython? - javascript

I'm trying to use Brython to run Python code in the browser, and to use websockets in that Python code.
I have working JavaScript code that can connect to the Websocket echo server at http://www.websocket.org/echo.html.
According to the documentation, the function JSObject can be used to manipulate JavaScript objects in Brython, but I can't get it to work using either ws = JSObject(WebSocket("ws://echo.websocket.org/")) or ws = JSObject(new WebSocket("ws://echo.websocket.org/")).
How can I make a simple "Hello World" example connecting to the echo server, in Python code, using Brython?
See also How to import library using Brython for using libraries that aren't built in to Brython (including the usual Python standard library).

Here is an example using the built-in websocket() function, included in py_websocket, and the server echo.websocket.org :
<html>
<head>
<meta charset="iso-8859-1">
<script src="/src/brython.js"></script>
<script type="text/python3">
def on_open():
# Web Socket is connected, send data using send()
data = doc["data"].value
if data:
ws.send(data)
alert("Message is sent")
def on_message(evt):
# message received from server
alert("Message received : %s" %evt.data)
def on_close(evt):
# websocket is closed
alert("Connection is closed")
ws = None
def _test():
global ws
# open a web socket
ws = websocket("wss://echo.websocket.org")
# attach functions to web sockets events
ws.on_open = on_open
ws.on_message = on_message
ws.on_close= on_close
def close_connection():
ws.close()
</script>
</head>
<body onload="brython(1)">
<input id="data">
<button onclick="_test()">Run WebSocket</button>
<p><button onclick="close_connection()">Close connection</button>
</body>
</html>
The code should be self-explanatory. The Brython site needs to be completed with more documentation about web sockets

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.

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()

Sample JavaScript can't connect to Ruby WebSocket server

I would like to fiddle with websockets a bit. I installed a Ruby gem called "websocket-ruby" (https://github.com/imanel/websocket-ruby) I started a pry / IRB session and typed:
require "websocket"
#handshake = WebSocket::Handshake::Server.new(:host => "localhost", :port => 8080,:secure=>true)
This starts a websocket server as far as I know. Then I opened in my browser the Javascript HTML page which attempt to connect to the server:
<!doctype html>
<html lang="en">
<head>
<title>Websocket Client</title>
</head>
<body>
<script>
var exampleSocket = new WebSocket("wss://localhost:8080");
exampleSocket.onopen = function (event) {
exampleSocket.send("Can you hear me?");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</script>
</body>
</html>
But it says in the console log:
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I tried different ports both in server and in the client respectively: 8081, 12345, but I always get this error message.
I have some idea about websocket and javascript, but not websocket-ruby.
I hope it will helpful you.
In nodejs.. server.js file, write below code
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
console.log("websocket Server is Running...");
wss.on('connection', function connection(ws) {
// Store the remote systems IP address as "remoteIp".
var remoteIp = ws.upgradeReq.connection.remoteAddress;
// Print a log with the IP of the client that connected.
console.log('Connection received: ', remoteIp);
// Add a listener which listens for the "message" event.
// When a "message" event is received, take the contents
// of the message and pass it to the broadcast() function.
ws.on('message', wss.broadcast);
});
wss.broadcast = function(msg) {
wss.clients.forEach(function each(client) {
client.send(msg);
})
};
In javascript...
var SERVER_URL = 'ws://localhost:8100';
//instead of localhost you can also use IP address of your system
var ws;
function connect() {
alert('connect');
ws = new WebSocket(SERVER_URL, []);
// Set the function to be called when a message is received.
ws.onmessage = handleMessageReceived;
// Set the function to be called when we have connected to the server.
ws.onopen = handleConnected;
// Set the function to be called when an error occurs.
ws.onerror = handleError;
}
function handleMessageReceived(data) {
// Simply call logMessage(), passing the received data.
logMessage(data.data);
}
function handleConnected(data) {
// Create a log message which explains what has happened and includes
// the url we have connected too.
var logMsg = 'Connected to server: ' + data.target.url;
// Add the message to the log.
logMessage(logMsg)
}
function handleError(err) {
// Print the error to the console so we can debug it.
console.log("Error: ", err);
}
function logMessage(msg) {
// with the new message.
console.log(msg);
}
/** This is the scope function that is called when a users hits send. */
function sendMessage{
ws.send(msg);
};
connect();
in html use one button to send message to websocket server
<button onclick="sendMessage('Hi Websocket')">send message</button>
To the best of my knowledge, the Ruby code you presented does not start a Websocket server... what it does is initiate a server-side parser.
To start a server you need to use an actual websocket server.
ActionCable (with Rails) uses the websocket-ruby library to parse websocket events and it uses nio4r to operate the actual server.
Faye have a similar solution and em-websockets use the websocket-ruby gem with EventMachine.
Other Ruby Websocket servers include Iodine, which uses the C library facil.io. Iodine is used by the framework plezi as well as independently.
Since you were trying to run an echo server, here's a quick example using the Plezi framework (you can use it as middleware in Sinatra or Rails)...
...place the following in a config.ru file:
require 'plezi'
class WebsocketSample
# HTTP index
def index
'Hello World!'
end
# called when Websocket data is recieved
#
# data is a string that contains binary or UTF8 (message dependent) data.
def on_message(data)
puts "Websocket got: #{data}"
write data
end
end
Plezi.route '/', WebsocketSample
run Plezi.app
To run the server, call (ignore the $ sign, it marks this code as terminal code):
$ iodine
notice: Iodine requires a BSD / Unix / Linux machine, such as macOS, Ubuntu, etc'. It won't work on windows.

python websocket handshake (RFC 6455)

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()

Categories

Resources