0

Having a small problem with a multithreaded socket server in Python 3. I can't seem to start my socket listening in its own thread. I'm probably way off base.

Borrowed the code here: How to make a simple multithreaded socket server in Python that remembers clients

But I need to listen for clients within a thread or at least in the background. Can't figure out what I'm doing wrong.

Here's my code:

import socket
from threading import Thread
from cmd import Cmd

class ThreadedServer(Thread):

  def __init__(self):
    self.host = "127.0.0.1"
    self.port = int(8080)
    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    self.sock.bind((self.host, self.port))

  def listen(self):
    self.sock.listen(5)
    print("[Info]: Listening for connections on {0}, port {1}".format(self.host,self.port))
    while True:
        print("Hello?") # Just debug for now
        client, address = self.sock.accept()
        client.settimeout(60)
        threading.Thread(target = self.listenToClient,args = (client,address)).start()

  def listenToClient(self, client, address):
    size = 1024
    while True:
        try:
            data = client.recv(size)
            if data:
                # Set the response to echo back the recieved data
                response = data
                client.send(response)
            else:
                raise error('Client disconnected')
        except:
            client.close()
            return False

class CommandInput(Cmd):
  # Able to accept user input here but is irrelevant right now
  pass

print("[Info]: Loading complete.")

clientThread = ThreadedServer().listen()
clientThread.start()

print("[Info]: Server ready!")

prompt = CommandInput()
prompt.prompt = '> '
prompt.cmdloop("[Info]: Type \'help\' for a list of commands and their descriptions/use")

As you can see I have some code after my listening part where I need to be able to accept input on the terminal. However, the code never gets there.

Here's the output quite simply:

[Info]: Loading complete.
[Info]: Listening for connections on 127.0.0.1, port 8080
Hello?

I'm expecting:

[Info]: Loading complete.
[Info]: Listening for connections on 127.0.0.1, port 8080
Hello?
[Info]: Type \'help\' for a list of commands and their descriptions/use
> 

with a cursor ready for me to type.

So how can I properly get my program to listen for clients in that loop in a proper thread so that I can enter prompts at the command line and process user input (for example one of the commands I want to implement is that of a client "send" which I would be able to send debug information to connected clients)

Thanks for any assistance you can provide.

Jguy
  • 583
  • 1
  • 11
  • 33
  • There are a few issues in the code. For example, after you run the script, how do you try to connect to the server? You can try accessing `127.0.0.1:8080` through your browser or creating another script that connects to this open socket. Also the line `clientThread.start()` is never reached by your program. Would suggest following a better source for a basic client/server model. One example you could try is [here](https://www.techbeamers.com/python-tutorial-write-multithreaded-python-server/) – jean Sep 03 '19 at 20:00
  • `clientThread.start()` may never be reached. I would still want the program to continue through listening for clients and allowing input on the server console as the server can do other things without the client connected. – Jguy Sep 03 '19 at 20:04
  • Please see a small sample code below which may help you a bit. I've added a `# change here` for lines I've updated. – jean Sep 03 '19 at 20:12

1 Answers1

1

This may not be the ideal structure for setting up what you want, but seems to solve the requirement you stated.

After launching this script on a terminal, you can make sample client connections by opening one, or more, browser tabs to localhost:8080

import socket
from threading import Thread
from cmd import Cmd

# basic threading tutorial: https://www.tutorialspoint.com/python3/python_multithreading.htm

class ThreadedServer(Thread):

  def __init__(self):
    Thread.__init__(self)  # change here
    self.host = "127.0.0.1"
    self.port = int(8080)
    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    self.sock.bind((self.host, self.port))

  def run(self):    # change here
    self.sock.listen(5)
    print("[Info]: Listening for connections on {0}, port {1}".format(self.host,self.port))
    while True:
        print("Hello?") # Just debug for now
        client, address = self.sock.accept()
        client.settimeout(60)
        Thread(target = self.listenToClient, args = (client,address)).start()   # change here

  def listenToClient(self, client, address):
    size = 1024
    while True:
        try:
            data = client.recv(size)
            if data:
                # Set the response to echo back the recieved data
                response = data
                client.send(response)
            else:
                raise error('Client disconnected')
        except:
            client.close()
            return False


class CommandInput(Cmd):
  # Able to accept user input here but is irrelevant right now
  pass

if __name__ == "__main__":
  print("[Info]: Loading complete.")

  server = ThreadedServer()  # change here
  server.start()  # change here

  print("[Info]: Server ready!")

  prompt = CommandInput()
  prompt.prompt = '> '
  prompt.cmdloop("[Info]: Type \'help\' for a list of commands and their descriptions/use")

jean
  • 973
  • 1
  • 11
  • 23
  • that's perfect. I will definitely take a look at your link. I'm still learning afterall, and this is a great start. As they say there are always a million ways of doing the same thing. – Jguy Sep 03 '19 at 20:44