16

I am a newbie in python sockets and am really troubled by the stubbornness of the socket.accept() method. I really need a way of ending a socket.accept() method or any other alternative to socket.accept() which runs one time only.

Neuron
  • 5,141
  • 5
  • 38
  • 59
cybernerd
  • 173
  • 1
  • 1
  • 6

2 Answers2

17

You have several options here:

  1. Close the listening socket from another thread - the accept() will raise an exception if it fails.
  2. Open a local connection to the listening socket - that makes the accept() return by design.
  3. Use an accept mechanism that can block on more than one synchronization object so that the wait can be signaled to return without a connection.
  4. Use a non-blocking alternative to accept(), (async like AcceptEx() and overlapped IO on Windows).
Niklas B.
  • 92,950
  • 18
  • 194
  • 224
Martin James
  • 24,453
  • 3
  • 36
  • 60
  • 1
    @NiklasB. - thanks. I don't have any Python, but the OP question is more a general TCP server issue and the same set of 'tricks' are needed in all languages. – Martin James Apr 10 '12 at 14:49
  • 1
    Can you give an example because as stated earlier i am a newbie....i am actually writing a server in pygtk. My problem is that the window hangs because of the socket.accept() call. – cybernerd Apr 11 '12 at 08:47
  • 1
    On OSX 10.10 with Python 2.7.6, (1) is unreliable. However, using a `quit_now` style flag in the accept loop and then connecting (2) to trigger a return from accept() works fine. – Harvey Jan 19 '15 at 17:19
  • 2
    Option #2 seems to be most appropriate for several of my applications. – Johnny Utahh Apr 17 '15 at 00:23
  • 2
    Could you show examples of these? You have no idea how useful they'd be. – byxor Dec 01 '16 at 17:11
  • Iam trying first method, but it still hangs. – Nikolai Ehrhardt Feb 26 '23 at 16:06
0

Iam posting this because accepted answer is incomplete, On Unix the circumstances are a little bit more complicated.

crossplatform code:

class KeyServer:

    HOST = "127.0.0.1"
    PORT = int(os.getenv("PL_CREDENTIAL_SERVER_PORT", "55955"))

    def __init__(self, args):
        self.args = args
        self.script_checker = ScriptChecker(args)
        self.sock = None

    def listen(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((KeyServer.HOST, KeyServer.PORT))
        self.sock.listen(20)

        while True:
            try:
                readable, _, _ = select.select([self.sock], [], [], 1.0)
                if self.sock in readable:
                    conn, addr = self.sock.accept()
                    conn.settimeout(0.5)
                    print(f"Connected by {addr}", flush=True)
                    connstream = conn
                    ServerThread(connstream, self).start()
            except Exception:
                traceback.print_exc()
                break

        try:
            self.sock.close()
        except Exception:
            pass

Used class Serverthread can now close() the socket. Without using select, the accept method will remain in an unusable state. Because it will wait for the sock to be readable and exactly this must be clarified before.

Nikolai Ehrhardt
  • 570
  • 4
  • 14