0

Currently, my code only allows a finite number of socket connections. This is determined by the variable No_Of_Connections.

My question is: how do I make it such that it is not finite? Meaning I do not have to hard code the number of connections. I would also need to be able to terminate or join the thread when the client closes the connection.

Any help is greatly appreciated. Thank you!

def Main():
    HOST = '192.168.2.9'
    PORT = 65533
    No_Of_Connections = 10

    trds = []

    s = socket(AF_INET, SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen(No_Of_Connections)

    print("Server is running on port: " + str(PORT))

    try:
        for i in range(No_Of_Connections):
            c, addr = s.accept()
            clients.append(c)
            t = Thread(target=clientHandler, args=(s, c, addr))
            trds.append(t)
            t.start()

        for t in trds:
            t.join()

    except KeyboardInterrupt:
        print("caught keyboard interrupt in main, exiting")
        s.close()

    except Exception as e:
        print('Socket Server error: ' + str(e))
Clifford
  • 88,407
  • 13
  • 85
  • 165
MDanial
  • 55
  • 6
  • 3
    Change `for i in range(No_Of_Connections):` to `while True:` – Ed Ward Feb 02 '20 at 08:22
  • 1
    ... and remove the _backlog_ argument from `s.listen(No_Of_Connections)`, it was unnecessary in any case. – Clifford Feb 02 '20 at 08:28
  • @EdWard if i do that, how would it terminate the thread when the user closes the connection? – MDanial Feb 02 '20 at 08:41
  • @Clifford u mean set it as s.listen() instead of s.listen(no_of_connections)? – MDanial Feb 02 '20 at 08:42
  • @MDanial: The argument for `listen` has absolutely nothing to do with the number of connections your code is able to accept. See [here](https://stackoverflow.com/questions/36594400/what-is-backlog-in-tcp-connections) for an explanation what this parameter is for instead. Also, you cannot have an unlimited number of sockets since the OS will put limits on this. But you can have at least the number not limited by the design of your application. – Steffen Ullrich Feb 02 '20 at 09:38
  • @SteffenUllrich Thank you for your answer and the link. Much appreciated – MDanial Feb 02 '20 at 10:03
  • @Clifford Thanks for your comment. I've made the necessary changes – MDanial Feb 02 '20 at 10:04
  • @SteffenUllrich : To be fair, I changed it to "unlimited". It previously said "infinite" (which is worse). I intended "unlimited" in the sense of not limited by the code implementation. Memory or OS limits will of course be a _limiting factor_. – Clifford Feb 02 '20 at 16:35
  • Regarding how you terminate the thread, you don't. Your original code accepts a finite number of connections and and terminates when all those connections terminate. If you are to accept an undefined number of connections you would not normally terminate when a connection is closed, because the connections may be made asynchronously at any time. The number of current connections is variable, including zero. Servers normally run until closed down by the server operatror, not in response to connections. – Clifford Feb 02 '20 at 16:40

1 Answers1

0

Thanks for the responses!!

I've edited my codes based on new responses.

from socket import *
from threading import Thread
from MySQLconnect import *

clients = []


def clientHandler(s, c, addr):
    print(addr, "is Connected")
    msg = 'Connected to server!'
    c.send(msg.encode('utf-8'))
    while True:
        try:
            data = c.recv(2048).decode('utf-8')
            if not data:
                # This occurs if client kills connection
                print('Connection closed by client: ' + str(addr))
                clients.remove(c)
                c.close()
                return
            if data:
                if 'sensor' in data:
                    MYSQL_thread = MySQL_connect()
                    msg = list()
                    # eg: sensor MQ-8 200
                    for word in data.split():
                        msg.append(word)
                    MYSQL_thread.insert_db(msg[1], msg[2])
                    print('Sensor >> ' + data)
                    broadcast_msg(s, c, 'Database updated')
                else:
                    print('Data >> ' + data)
                    broadcast_msg(s, c, data)
        except Exception as e:
            print('clientHandler error: ' + str(e))


def broadcast_msg(s, c, message):
    global clients
    if not isinstance(message, str):
        message = str(message)
    for client in clients:
        if client != s and client != c:
            # Don't send to server and source of message
            try:
                client.send(message.encode('utf-8'))
            except Exception as e:
                print('Broadcast msg error:' + str(e))


def Main():
    HOST = '192.168.1.9'
    PORT = 65533

    trds = []

    s = socket(AF_INET, SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen()

    print("Server is running on port: " + str(PORT))

    try:
        while True:
            c, addr = s.accept()
            clients.append(c)
            t = Thread(target=clientHandler, args=(s, c, addr), daemon=True)
            trds.append(t)
            t.start()

    except (KeyboardInterrupt, SystemExit):
        print("caught keyboard interrupt in main, exiting")
        s.close()

    except Exception as e:
        print('Socket Server error: ' + str(e))
        s.close()


if __name__ == '__main__':
    Main()
MDanial
  • 55
  • 6
  • Make the threads daemon threads. They close when the main (server) thread exits, and don’t need to be joined. They end when the thread target function returns, so just close the client socket just before the client function ends. – Mark Tolonen Feb 02 '20 at 17:34
  • @MarkTolonen Thanks for your input. I've edited my codes accordingly – MDanial Feb 04 '20 at 10:38