-
-
Notifications
You must be signed in to change notification settings - Fork 540
Send to two clients in one server?How can I do? #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Well it's up to you to implement this, most likely with a variant of the Subscriber pattern. See https://github.com/aaugustin/django-c10k-demo/blob/master/gameoflife/views.py for an example. |
sorry, the django-c10k-demo is to complex to me, it mixed django code, i can't understand it. |
Have a look at https://static.myks.org/data/20130905-DjangoCon-Real-time_Web.pdf starting at slide 32. It's a simpler example. |
I can't open this link, maybe that site was banned by the government. :( |
Well there's plenty of resources on the Internet to learn concurrent programming patterns, I'm not the right person to ask. Good luck. |
this demo make a websocket server, but I don't know how to rewrite it use websockets lib. #!/usr/bin/env python
import socket, hashlib, base64, threading
class PyWSock:
MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
HSHAKE_RESP = "HTTP/1.1 101 Switching Protocols\r\n" + \
"Upgrade: websocket\r\n" + \
"Connection: Upgrade\r\n" + \
"Sec-WebSocket-Accept: %s\r\n" + \
"\r\n"
LOCK = threading.Lock()
clients = []
def recv_data (self, client):
# as a simple server, we expect to receive:
# - all data at one go and one frame
# - one frame at a time
# - text protocol
# - no ping pong messages
data = client.recv(512)
if(len(data) < 6):
raise Exception("Error reading data")
# FIN bit must be set to indicate end of frame
assert(0x1 == (0xFF & data[0]) >> 7)
# data must be a text frame
# 0x8 (close connection) is handled with assertion failure
assert(0x1 == (0xF & data[0]))
# assert that data is masked
assert(0x1 == (0xFF & data[1]) >> 7)
datalen = (0x7F & data[1])
#print("received data len %d" %(datalen,))
str_data = ''
if(datalen > 0):
mask_key = data[2:6]
masked_data = data[6:(6+datalen)]
unmasked_data = [masked_data[i] ^ mask_key[i%4] for i in range(len(masked_data))]
str_data = bytearray(unmasked_data).decode('utf8')
return str_data
def broadcast_resp(self, data):
# 1st byte: fin bit set. text frame bits set.
# 2nd byte: no mask. length set in 1 byte.
resp = bytearray([0b10000001, len(data)])
# append the data bytes
for d in data.encode('utf8'):
resp.append(d)
self.LOCK.acquire()
for client in self.clients:
try:
client.send(resp)
except:
print("error sending to a client")
self.LOCK.release()
def parse_headers (self, data):
headers = {}
lines = data.decode().splitlines()
for l in lines:
parts = l.split(": ", 1)
if len(parts) == 2:
headers[parts[0]] = parts[1]
headers['code'] = lines[len(lines) - 1]
return headers
def handshake (self, client):
print('Handshaking...')
data = client.recv(2048)
headers = self.parse_headers(data)
print('Got headers:')
for k, v in headers.items():
print(k, ':', v)
key = headers['Sec-WebSocket-Key']
resp_data = self.HSHAKE_RESP % base64.b64encode(hashlib.sha1(\
(key+self.MAGIC).encode()).digest()).decode()
print(('Response: [%s]' % (resp_data,)))
return client.send(resp_data.encode())
def handle_client (self, client, addr):
self.handshake(client)
try:
while 1:
data = self.recv_data(client)
print(("received [%s]" % (data,)))
self.broadcast_resp(data)
except Exception as e:
print(("Exception %s" % (str(e))))
print(('Client closed: ' + str(addr)))
self.LOCK.acquire()
self.clients.remove(client)
self.LOCK.release()
client.close()
def start_server (self, port):
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', port))
s.listen(5)
while(1):
print ('Waiting for connection...')
conn, addr = s.accept()
print(('Connection from: ' + str(addr)))
threading.Thread(target = self.handle_client, args = (conn, addr)).start()
self.LOCK.acquire()
self.clients.append(conn)
self.LOCK.release()
ws = PyWSock()
ws.start_server(4545) |
Connections are handled by asyncio. Learn first to do it with asyncio; websocket behaves similarly. |
I modify c10k demo, add a broadcast url, it running ok, code as below: clients = set()
@websocket
def broadcast(ws):
while True:
msg = yield from ws.recv()
clients.add(ws)
for client in clients:
if client.open:
yield from client.send(msg) I want make a broadcast server without django. so i modify server.py in example dir. when i open one webpage, it running ok. but when i open two webpages, the broadcast message appear twice at one page(the current focus page). code as below: import asyncio
import websockets
clients = set()
@asyncio.coroutine
def hello(websocket, uri):
while True:
msg = yield from websocket.recv()
clients.add(websocket)
for client in clients:
if client.open:
yield from websocket.send(msg)
start_server = websockets.serve(hello, 'localhost', 4545)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever() if i rewrite it use ws4py lib, it running all ok. code as below: import asyncio
from ws4py.async_websocket import WebSocket
from ws4py.server.tulipserver import WebSocketProtocol
loop = asyncio.get_event_loop()
clients = set()
class EchoWebSocket(WebSocket):
def received_message(self, message):
clients.add(self)
for client in clients:
client.send(message.data, message.is_binary)
def start_server():
proto_factory = lambda: WebSocketProtocol(EchoWebSocket)
return loop.create_server(proto_factory, 'localhost', 4545)
s = loop.run_until_complete(start_server())
print('serving on', s.sockets[0].getsockname())
loop.run_forever() client html file as below: <!DOCTYPE html>
<html>
<head>
<title>Websocket Demo</title>
<style>
#messages {
border: dotted 1px #444444;
font: 12px arial,sans-serif;
}
#messages > p {
padding: 0px;
margin: 0px;
}
</style>
<script>
var messages;
var form;
var inputBox;
function log_msg(msg) {
var p = document.createElement("p");
p.innerHTML = msg;
messages.appendChild(p);
}
function doInit() {
inputBox = document.getElementById("message");
messages = document.getElementById("messages");
form = document.getElementById("form");
var s;
try {
var host = "ws://localhost:4545/";
if(window.location.hostname) {
host = "ws://" + window.location.hostname + ":4545/";
}
s = new WebSocket(host);
s.onopen = function (e) { log_msg("connected..."); };
s.onclose = function (e) { log_msg("connection closed."); };
s.onerror = function (e) { log_msg("connection error."); };
s.onmessage = function (e) { log_msg("message: " + e.data); };
} catch (ex) {
log_msg("connection exception:" + ex);
}
form.addEventListener("submit", function (e) {
e.preventDefault();
s.send(inputBox.value);
inputBox.value = "";
}, false);
}
</script>
</head>
<body onload="doInit()">
<form id="form">
<input type="text" id="message">
<button type="submit">Send</button>
</form>
<br/>
<div id="messages"></div>
</body>
</html> |
Cool, use ws4py then! |
I want send a message to two clients, how can i do? I can not find the client connect handle or client addr!
The text was updated successfully, but these errors were encountered: