Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » Network
  • » Многопоточный TCP сервер, база данных и очереди [RSS Feed]

#1 Окт. 17, 2012 23:35:06

battlecoder
Зарегистрирован: 2012-10-17
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

Всем привет.

Есть сервер. Сначала думал над тем, как вручную реализовать, потом наткнулся на http://docs.python.org/py3k/library/socketserver.html и решил, что это то, что мне надо.

Собственно, вся реализация сервера:

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

Обрабатывает все запросы некий класс

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = str(self.request.recv(1024), 'ascii')
        cur_thread = threading.current_thread()
        response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
        self.request.sendall(response)

Всё работает как надо (если скопировать пример из дока). Нюанс вот в чём. Мне нужно чтобы сервер обслуживал многих клиентов, а они могли выполнять какие-то операции. Например, пользователь хочет зарегистрироваться - для этого клиент посылает специальный запрос, сервер его обрабатывает, и он должен добавить запись в базу данных (использую sqlite).

Но sqlite нельзя использовать из множества потоков!! Решить проблему можно так - выбрать один поток, который и будет писать в базу данных и выполнять все операции. Можно, например взять очередь http://docs.python.org/py3k/library/queue

сделал примерно так, создаю очередь и делаю её полем класса:

tasks = queue.Queue()
ThreadedTCPRequestHandler.tasks = tasks

Также передаю в специальный класс обработчик, которую запускаю в отдельном потоке (и этот поток всегда одинаковый, запускаю его ОДИН раз)

worker = Worker(tasks)

Ну реализация примерно такая

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = str(self.request.recv(1024), 'ascii')
        ThreadedTCPRequestHandler.tasks.put(data)
        # что посылать в ответ??
        self.request.sendall(???)
class Worker:
    def __init__(self, tasks):
        self.tasks = tasks
    def do(self):
        while True:
            item = q.get()
            # делаю тут что-то, например, работаю с базой данных sqlite
            q.task_done()

Собственно, мне нужно узнать результат выполнения, выполнена ли команда успешно или вообще не выполнена… и вернуть результат клиент (через sock.sendall(b'что-то'). Как это сделать? %) мне создать ещё одну очередь? такой вариант наверное не прокатит…

Я пробовал просто отправлять в очередь tasks = queue.Queue() экземпляры сокетов (и делать sock.recv/sock.send уже из класса Worker) - но такой вариант вообще не работает, сокет становится закрытым… то есть с сокетом можно получается работать только из того потока, который обслуживает клиента.

Что делать? %)

Офлайн

#2 Окт. 19, 2012 01:22:26

mindless
Зарегистрирован: 2012-04-01
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

можно сделать каждому потоку очередь в которую worker будет скидывать результат

def handle(self):
    data = str(self.request.recv(1024), 'ascii')
    myname = threading.current_thread().name
    ThreadedTCPRequestHandler.tasks.put((myname, data))
    result = ThreadedTCPRequestHandler.results[myname].get()
    self.request.sendall(result)
while True:
    name, item = q.get()
    # делаю тут что-то, например, работаю с базой данных sqlite
    ThreadedTCPRequestHandler.results[name].put(smth)
    q.task_done()

upd: почему подсветка по умолчанию не python?
upd2: если писать code] вручную

Отредактировано mindless (Окт. 19, 2012 02:35:52)

Офлайн

#3 Окт. 19, 2012 02:13:56

odnochlen
Зарегистрирован: 2012-06-28
Сообщения: 794
Репутация: +  14  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

mindless
upd: почему подсветка по умолчанию не python?
У меня питон, ЧЯДНТ?

Офлайн

#4 Окт. 19, 2012 18:36:44

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

Если вы хотите писать сами низкоуровневые вещи, рекомендую изучить хотя бы потоки.
Вот есть хороший пример сервера, который создает пул потоков-обработчиков для каждого клиента:
http://keysolutions.ru/articles/osnovy-raboty-s-potokami-v-python



Офлайн

#5 Ноя. 5, 2012 11:35:00

battlecoder
Зарегистрирован: 2012-10-17
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

Мм, спасибо за ссылку. Может подумаю о том, чтобы создать пул потоков.

С этим вроде бы разобрался (без пула), сделал так, чтобы всё отправлялось через один и тот же сокет, и через него же принималось.
Вкратце - есть поток, который прослушивает сокет, и если пришло сообщение - парсит его. Если это notification, кладёт его в одну очередь, а если response - в другую.
И другой поток (по сути главный поток) является клиентом, он может отправлять запросы (request) в этот же самый socket, но response (ответы) он оттуда не берёт, а вместо этого запрашивает их из очереди (в которую их кладёт первый поток).

Довольно гибкая система, хотя код IMHO всё равно получился ужасен не привык я пока к питону. Но работает. Как надо.

Осталось с GUI нормальным разобраться ну и с прочими тонкостями этого приложения. Но это уже совсем другая история.

Офлайн

#6 Дек. 17, 2012 20:31:33

altRUist
Зарегистрирован: 2012-12-17
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

battlecoder
Нюанс вот в чём. Мне нужно чтобы сервер обслуживал многих клиентов, а они могли выполнять какие-то операции. Например, пользователь хочет зарегистрироваться - для этого клиент посылает специальный запрос, сервер его обрабатывает, и он должен добавить запись в базу данных (использую sqlite).Но sqlite нельзя использовать из множества потоков!! Решить проблему можно так - выбрать один поток, который и будет писать в базу данных и выполнять все операции.
я, конечно, сам “со вчера” изучаю Python, но, мне кажется, если мультипотоковое приложение отправляет все потоки работы с базой данных к одному потоку, то какой смысл тогда этой мультипоточности?
скажите а как это sqlite не работает в потоках?
есть ли какой-то аналог perl-овского DBI?

может кто-нибудь натыкался на пример приложения, которое использует os.fork(), SocketServer, threading, и работает с базами данных mysql (извините за мою наглость ))

Отредактировано altRUist (Дек. 17, 2012 20:48:09)

Офлайн

#7 Дек. 17, 2012 21:11:27

Soteric
От:
Зарегистрирован: 2010-09-19
Сообщения: 352
Репутация: +  20  -
Профиль   Отправить e-mail  

Многопоточный TCP сервер, база данных и очереди

Если запрос к базе занимает малую часть от общего времени обработки сообщения, то преимущество все равно будет. Да, это станет одним из узких мест в системе, но вероятно не самым тормозящим.



Офлайн

  • Начало
  • » Network
  • » Многопоточный TCP сервер, база данных и очереди[RSS Feed]

Board footer

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

Powered by DjangoBB

Lo-Fi Version