1

I'm trying to create a threaded TCP socket server that can handle multiple socket request at a time.

To test it, I launch several thread in the client side to see if my server can handle it. The first socket is printed successfully but I get a [Errno 32] Broken pipe for the others. I don't know how to avoid it.

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()
NicoAdrian
  • 946
  • 1
  • 7
  • 18

1 Answers1

0

It's a little bit difficult to determine what exactly you're expecting to happen, but I think the proximate cause is that you aren't giving your clients time to run before killing the server.

When you construct a Thread object and call its start method, you're creating a thread, and getting it ready to run. It will then be placed on the "runnable" task queue on your system, but it will be competing with your main thread and all your other threads (and indeed all other tasks on the same machine) for CPU time.

Your multiple threads (main plus others) are also likely being serialized by the python interpreter's GIL (Global Interpreter Lock -- assuming you're using the "standard" CPython) which means they may not have even gotten "out of the gate" yet.

But then you're shutting down the server with server_close() before they've had a chance to send anything. That's consistent with the "Broken Pipe" error: your remaining clients are attempting to write to a socket that has been closed by the "remote" end.

You should collect the thread objects as you create them and put them in a list (so that you can reference them later). When you're finished creating and starting all of them, then go back through the list and call the .join method on each thread object. This will ensure that the thread has had a chance to finish. Only then should you shut down the server. Something like this:

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()

One other thing to note is that all of your clients are sharing the same single connection to send to the server, so that your server will never create more than one thread: as far as it's concerned, there is only a single client. You should probably move the graphitesend.init into the client function if you actually want separate connections for each client.

(Disclaimer: I know nothing about graphitesend except what I could glean in a 15 second glance at the first result in google; I'm assuming it's basically just a wrapper around a TCP connection.)

Gil Hamilton
  • 11,973
  • 28
  • 51
  • The graphitesend library sends TCP socket. The code I posted was an example but in fact, in my client side, all the threads share the same connection, as you mentionned. How can I allow the threads to use the same connection and make it work ? – NicoAdrian Jun 01 '18 at 10:10