Сразу к делу.
Есть сервер. Сначала думал над тем, как вручную реализовать, потом наткнулся на 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) - но такой вариант вообще не работает, сокет становится закрытым... то есть с сокетом можно получается работать только из того потока, который обслуживает клиента.
Что делать? %)