jeudi 16 juin 2016

Python Chat Server with Threads and multiclients

My goal is to take a provided framework python file and add the functionality to make a chat server that handles multiple clients. I have done edits in the chat_output, server, and client functions, and are currently inside the multi-line comments.

First step is to get the client to connect without issues. Then I would need to add a raw_input() call so that a user can type something, send it to the server, and then have the server sendall() to the clients.

import socket

class Stream(object):
    " abstract "
    def write(self,data):
        pass
    def read(self):
        pass

class TCPStream(Stream):
    def __init__(self,the_socket):
        self.s = the_socket
        self.address = None
    def read(self,amount=None):
        if amount is None:
            return self.s.recv(4096)
        else:
            return self.s.recv(amount)
    def set_address(self,address):
        self.address = address
    def get_address(self):
        return self.address
    def write(self,data):
        self.s.sendall(data)
    def __del__(self):
        self.s.close()
    def shutdown(self):
        self.s.shutdown(socket.SHUT_WR)

class Socket(object):
    pass

class TCPBaseSocket(Socket):
    def __init__(self,port):
        self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.port = port

class TCPReceivingSocket(TCPBaseSocket):
    def __init__(self,port,address=''):
        super().__init__(port)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.s.bind((address,self.port))
        self.s.listen(1)
    def connection(self):
        sc, sockname = self.s.accept()
        result = TCPStream(sc)
        result.set_address(sockname)
        return result

class TCPSendingSocket(TCPBaseSocket):
    def __init__(self,port,address):
        super().__init__(port)
        self.s.connect((address,port))
        self._stream = TCPStream(self.s)
        self._stream.set_address((address,port))
    def stream(self):
        return self._stream

if __name__ == "__main__":
    import argparse
    import threading
    import sys

    def chat_input(stream):
        """
            Enter your code here, shouldn't need to be more than 10 lines of code
        """

        pass

    def chat_output(stream):        
        """
        Enter your code here, shouldn't need to be more than 10 lines of code


        #stream = TCPStream(stream)
        s = TCPStream(stream)
        while True:
            data = s.read()    #s.recv(4096)
            if not data:
                print("Disconnected from chat server")
                break
            #stream.write(data)      #sendall(data)
        """


    def server(interface,port):
        """
        Enter your code here, shouldn't need to be more than 10 lines of code

        tsc = TCPReceivingSocket(port, interface)
            print("Server is running.....n")

        addr = tsc.connection().get_address()
        print(addr, " is now connected!n")
        """

        pass
        server_input_thread = threading.Thread(target = chat_input, args = (tsc,))
        server_output_thread = threading.Thread(target = chat_output, args = (tsc,))

        server_input_thread.start()
        server_output_thread.start()
        server_input_thread.join()
        server_output_thread.join()

    def client(interface,port):
        """
        Enter your code here, shouldn't need to be more than 10 lines of code

        tsc = TCPSendingSocket(port, interface)
        """

        pass
        client_input_thread = threading.Thread(target = chat_input, args=(tsc,))
        client_output_thread = threading.Thread(target = chat_output, args=(tsc,))

        client_input_thread.start()
        client_output_thread.start()
        client_input_thread.join()
        client_output_thread.join()

    choices = {'client':client,'server':server}
    parser = argparse.ArgumentParser(description='Chat via TCP')
    parser.add_argument('role',choices=choices,help="which role to take")
    parser.add_argument('host',help='interface the server listens at; host the client sends to')
    parser.add_argument('-p',metavar='PORT',type=int,default=1060,help='TCP port (default 1060)')
    args = parser.parse_args()
    function=choices[args.role]
    function(args.host,args.p)

For those who are running this, use the command line:

python3 [filename].py server localhost

python3 [filename].py client localhost


With my code uncommented: The server connects. Once I initiate a client, this shoots an error (abbreviated):

line (21?) in read
return self.s.recv(4096)
AttributeError: 'TCPSendingSocket' object has no attribute 'recv'

and also causes

Exception:
self.s.close()
AttributeError: 'TCPSendingSocket' object has no attribute 'close'

The server then gets the same errors except "TCPReceivingSocket"

Aucun commentaire:

Enregistrer un commentaire