Многопоточный TCP-сокет - PullRequest
0 голосов
/ 31 мая 2018

Я пытаюсь создать многопоточный сервер сокетов TCP, который может обрабатывать несколько запросов сокетов одновременно.

Чтобы проверить это, я запускаю несколько потоков на стороне клиента, чтобы посмотреть, сможет ли мой сервер обработать его.,Первый сокет напечатан успешно, но я получаю [Errno 32] Broken pipe для остальных.Я не знаю, как этого избежать.

import threading
import socketserver
import graphitesend


class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024)
        if data != "":
            print(data)

class ThreadedTCPServer(socketserver.ThreadingTCPServer):
    allow_reuse_address = True

    def __init__(self, host, port):
        socketserver.ThreadingTCPServer.__init__(self, (host, port), ThreadedTCPRequestHandler)

    def stop(self):
        self.server_close()
        self.shutdown()

    def start(self):
        threading.Thread(target=self._on_started).start()

    def _on_started(self):
        self.serve_forever()

def client(g):
    g.send("test", 1)

if __name__ == "__main__":
    HOST, PORT = "localhost", 2003
    server = ThreadedTCPServer(HOST, PORT)
    server.start()
    g = graphitesend.init(graphite_server = HOST, graphite_port = PORT)
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    server.stop()

1 Ответ

0 голосов
/ 01 июня 2018

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

Когда высоздайте объект Thread и вызовите его метод start, вы создаете поток и готовите его к работе.Затем он будет помещен в очередь «запускаемых» задач в вашей системе, но он будет конкурировать с вашим основным потоком и всеми другими вашими потоками (и фактически всеми другими задачами на той же машине) за время ЦП.

Ваши несколько потоков (основной плюс другие) также, вероятно, сериализуются GIL интерпретатора Python ( Global Interpreter Lock - при условии, что вы используете "стандартный" CPython), что означает, что они, возможно, даже не получили"вне ворот" пока нет.

Но затем вы выключаете сервер с помощью server_close(), прежде чем они смогут что-либо отправить.Это согласуется с ошибкой «Broken Pipe»: ваши оставшиеся клиенты пытаются записать в сокет, который был закрыт «удаленным» концом.

Вы должны собирать объекты потока по мере их создания и помещать ихв списке (чтобы вы могли ссылаться на них позже).Когда вы закончите создавать и запускать их все, вернитесь в список и вызовите метод .join для каждого объекта потока.Это обеспечит возможность завершения потока.Только тогда вы должны выключить сервер.Примерно так:

threads = []
for n in range(7):
    th = threading.Thread(target=client, args=(g,))
    th.start()
    threads.append(th)

# All threads created. Wait for them to finish.
for th in threads:
    th.join()

server.stop()

Еще одна вещь, которую стоит отметить, это то, что все ваши клиенты используют одно и то же соединение для отправки на сервер, так что ваш сервер никогда не создаст более одного потока: насколькопоскольку это касается, есть только один клиент.Вам, вероятно, следует переместить graphitesend.init в функцию клиента, если вы действительно хотите иметь отдельные соединения для каждого клиента.

(Отказ от ответственности: я ничего не знаю о graphitesend, кроме того, что я мог бы получить за 15 секунд, глядя напервый результат в Google; я предполагаю, что это просто оболочка для TCP-соединения.)

...