Уведомления

Группа в Telegram: @pythonsu

#1 Июль 15, 2014 14:43:00

Hyyudu
Зарегистрирован: 2014-07-15
Сообщения: 10
Репутация: +  1  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

Добрый день, уважаемые форумчане!
Решил создать веб-приложение: клиент на JS, сервер на Python, обмен данными через websockets. Приложение - наподобие карточной игры: в одной партии конечное число участников (до 5), количество одновременно играемых партий на сервере ограничено только мощностью (по факту вряд ли больше 10 одновременно будет), одна партия конечной продолжительности. Клиенты внутри одной партии должны иметь доступ к одному и тому же набору данных, наборы данных в двух разных партиях никак не связаны между собой.
Как бы вы посоветовали строить схему взаимодействия “клиент-сервер” в такой системе? Обязательно ли для каждого подключившегося клиента делать threading.Thread(…).start(), или можно как-то обойтись одним главным потоком, получать данные параллельно со всех подключенных клиентов и обрабатывать их? Сервер сам по себе не генерирует никаких событий, а выдает некий объем информации всем участникам партии только в ответ на пришедший с одного из клиентов запрос.

Офлайн

#2 Июль 15, 2014 14:47:35

Singularity
Зарегистрирован: 2011-07-28
Сообщения: 1387
Репутация: +  75  -
Профиль   Отправить e-mail  

Офлайн

#3 Июль 15, 2014 14:56:51

Hyyudu
Зарегистрирован: 2014-07-15
Сообщения: 10
Репутация: +  1  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

За ссылки спасибо, но хочется сначала самому попробовать на вкус всю эту низкоуровневую кухню, а потом уже пробовать 100500 фреймворков.

Офлайн

#4 Июль 16, 2014 15:50:25

Hyyudu
Зарегистрирован: 2014-07-15
Сообщения: 10
Репутация: +  1  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

Первые шаги сделаны, все-таки решил обойтись без Tornado и Flask (тем более, что у меня все равно стоит Apache, и Питон работает под ним же). Написан клиент, написан (в самом базовом виде) сервер: в бесконечном цикле делается socket.accept() и для каждого нового клиента запускается thread, в котором крутится следующая функция:

def userloop(conn, addr):
	data = conn.recv(1024);
	if len(data) ==0:
		return;
	conn.send(create_handshake(data))
	print "Handshake with",addr[1],'ok!'
	while 1:
		data = conn.recv(1024);
		if len(data)>2:
			msg = unpack_frame(data)['payload'];
		else:
			msg = '';
		if (msg== ''):
			print addr[1],' disconnected!'
			break;
		else:
			 process_msg(msg, conn, addr)
Клиенты подключаются, отправляют сообщения, получают на них ответы, все прекрасно. Проблема теперь состоит в следующем: если клиент со своей стороны посылает socket.close(), то корректно завершается его собственный thread, не трогая все остальные. Но если в браузере закрыть вкладку или обновить страницу, то сначала от этого клиента приходит кусок данных, начинающийся с байтов 136,130, а потом всем клиентам приходит сообщение от сервера, что они отсоединены, а на сервер от всех клиентов начинают бесконечным потоком идти пустые блоки данных (в моем случае этот бесконечный поток сразу обрывается, поскольку отрабатывает секция print addr,' disconnected!'; break
Кто знает, как корректно обработать на сервере ситуацию, когда на клиенте происходит перезагрузка или закрытие страницы?

Офлайн

#5 Июль 17, 2014 14:48:47

Hyyudu
Зарегистрирован: 2014-07-15
Сообщения: 10
Репутация: +  1  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

Спасение оказалось в паре строк на стороне клиента:
window.onbeforeunload = function() {
socket.close();
}

Офлайн

#6 Июль 19, 2014 20:43:50

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

Hyyudu
Обязательно ли для каждого подключившегося клиента делать threading.Thread(…).start(), или можно как-то обойтись одним главным потоком, получать данные параллельно со всех подключенных клиентов и обрабатывать их?
Можно, для этого есть асинхронные фреймворки, (один поток и куча висящих клиентов).
Пример asyncio (стандартный модуль из py3.4) + websockets, для каждого клиента будет запущен свой “message”, для этого не нужен свой велосипед.
import asyncio
import websockets
 
@asyncio.coroutine
def message(websocket, path):
    while True:
        data = yield from websocket.recv()
        yield from websocket.send(data)
 
start_server = websockets.serve(message, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Отредактировано o7412369815963 (Июль 19, 2014 20:45:29)

Офлайн

#7 Июль 19, 2014 21:58:31

Hyyudu
Зарегистрирован: 2014-07-15
Сообщения: 10
Репутация: +  1  -
Профиль   Отправить e-mail  

Архитектура websocket-приложения

Спасибо!

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version