Python 3.4, TypeError for socket issues
Question: I don't quite understand the encode/decode in python. I've tried alsorts and
looked here to find similar but I cannot find some. This is the code in
question:

    
    
    import sys
    import socket
    import threading
    import time
    
    QUIT = False
    
    
    class ClientThread(threading.Thread):  # Class that implements the client threads in this server
        def __init__(self, client_sock):  # Initialize the object, save the socket that this thread will use.
            threading.Thread.__init__(self)
            self.client = client_sock
    
        def run(self):  # Thread's main loop. Once this function returns, the thread is finished and dies.
            global QUIT  # Need to declare QUIT as global, since the method can change it
            done = False
            cmd = self.readline()  # Read data from the socket and process it
            while not done:
                if b'quit' == cmd:
                    self.writeline('Ok, bye')
                    QUIT = True
                    done = True
                elif b'bye' == cmd:
                    self.writeline('Ok, bye')
                    done = True
                else:
                    self.writeline(self.name).encode('utf-8')
                    cmd = self.readline()
    
                self.client.close()  # Make sure socket is closed when we're done with it
                return
    
        def readline(self):  # Helper function, read up to 1024 chars from the socket, and returns them as a string
            result = self.client.recv(1024)
            if None != result:  # All letters in lower case and without and end of line markers
                result = result.strip().lower()
            return result
    
        def writeline(self, text):  # Helper func, writes the given string to the socket with and end of line marker at end
            self.client.send(bytes(text.strip() + '\n'))
    

In this case, I get:

    
    
    TypeError: string argument without an enconding.
    

This is on the line:

    
    
    self.writeline('ok bye')
    

and also the line:

    
    
    self.client.send(bytes(text.strip() + '\n'))  
    

deleting the bytes part gives me another error:

    
    
    TypeError: 'str' does not support the buffer interface  
    

And also references the two lines from above. I've tried a combination of
`encode(utf-8)` on both with no help.  
I think I'm grossly misunderstanding what is wrong here. I know that `bytes`
need to be sent, but when I do, it gives a concatenated error. Stuck in a vile
loop.  
Any clarification would be greatly appreciated, thank you!

This is the full code with the additions from the community help thus far:

    
    
    import sys
    import socket
    import threading
    import time
    
    QUIT = False
    
    
    class ClientThread(threading.Thread):  # Class that implements the client threads in this server
        def __init__(self, client_sock):  # Initialize the object, save the socket that this thread will use.
            threading.Thread.__init__(self)
            self.client = client_sock
    
        def run(self):  # Thread's main loop. Once this function returns, the thread is finished and dies.
            global QUIT  # Need to declare QUIT as global, since the method can change it
            done = False
            cmd = self.readline()  # Read data from the socket and process it
            while not done:
                if b'quit' == cmd:
                    self.writeline('Ok, bye'.encode('utf-8'))
                    QUIT = True
                    done = True
                elif b'bye' == cmd:
                    self.writeline('Ok, bye')
                    done = True
                else:
                    self.writeline(str(self.name).encode('utf-8'))
                    cmd = self.readline()
    
                self.client.close()  # Make sure socket is closed when we're done with it
                return
    
        def readline(self):  # Helper function, read up to 1024 chars from the socket, and returns them as a string
            result = self.client.recv(1024)
            if None != result:  # All letters in lower case and without and end of line markers
                result = result.strip().lower()
            return result
    
        def writeline(self, text):  # Helper func, writes the given string to the socket with and end of line marker at end
            self.client.send((text.strip() + '\n').encode("utf-8"))
    
    
    class Server:  # Server class. Opens up a socket and listens for incoming connections.
        def __init__(self):  # Every time a new connection arrives, new thread object is created and
            self.sock = None  # defers the processing of the connection to it
            self.thread_list = []
    
        def run(self):  # Server main loop: Creates the server (incoming) socket, listens > creates thread to handle it
            all_good = False
            try_count = 0  # Attempt to open the socket
            while not all_good:
                if 3 < try_count:  # Tried more than 3 times without success, maybe post is in use by another program
                    sys.exit(1)
                try:
                    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # Create the socket
                    port = 80
                    self.sock.bind(('127.0.0.1', port))  # Bind to the interface and port we want to listen on
                    self.sock.listen(5)
                    all_good = True
                    break
                except socket.error:
                    print('Socket connection error... Waiting 10 seconds to retry.')
                    del self.sock
                    time.sleep(10)
                    try_count += 1
    
            print('Server is listening for incoming connections.')
            print('Try to connect through the command line with:')
            print('telnet localhost 80')
            print('and then type whatever you want.')
            print()
            print("typing 'bye' finishes the thread. but not the server",)
            print("eg. you can quit telnet, run it again and get a different ",)
            print("thread name")
            print("typing 'quit' finishes the server")
    
            try:
                while not QUIT:
                    try:
                        self.sock.settimeout(0.500)
                        client = self.sock.accept()[0]
                    except socket.timeout:
                        time.sleep(1)
                        if QUIT:
                            print('Received quit command. Shutting down...')
                            break
                        continue
                    new_thread = ClientThread(client)
                    print('Incoming Connection. Started thread ',)
                    print(new_thread.getName())
                    self.thread_list.append(new_thread)
                    new_thread.start()
                    for thread in self.thread_list:
                        if not thread.isAlive():
                            self.thread_list.remove(thread)
                            thread.join()
            except KeyboardInterrupt:
                print('Ctrl+C pressed... Shutting Down')
            except Exception as err:
                print('Exception caught: %s\nClosing...' % err)
            for thread in self.thread_list:
                thread.join(1.0)
                self.sock.close()
    
    if "__main__" == __name__:
        server = Server()
        server.run()
    
    print('Terminated')
    

In the traceback I get this exactly:

    
    
    Exception in Thread-1:
    Traceback (most recent call last):
    File: "C:\Python34\liv\threading.py", line 920, in _bootstrap_inner
             self.run()
    File: "C:/Users/Savag/PycharmProjects/lds_system/Socketthread2.py", line 20 in run
             self.writeline('Ok, bye'.encode("utf-8"))
    File: "C:/Users/Savag/PycharmProjects/lds_system/Socketthread2.py", Line 40, in writeline
    self.client.send((text.strip() + '\n').encode("utf-8"))
    


Answer: When you use `self.writeline('Ok bye'.encode('utf8'))` you are now passing a
`bytes` object to your `writeline()` method. In that method, you are then
concatenating another string to it `text.strip() + '\n'`, causing you to try
to concatenate a `bytes` and a `str` object.

Either have your `writeline` method handle the encoding, or have it handle
`bytes` only. If you do the latter, make sure your `readline()` method then
_decodes_ the data it reads from the socket, to be consistent.

In other words, pick an abstraction level at which you convert from text to
bytes, and use it consistently:

    
    
    def readline(self):
        """Read up to 1024 bytes and return this as a string
    
        Returns None if there was no data to read.
    
        """
        result = self.client.recv(1024)
        if result is not None:
            result = result.strip().lower().decode('utf8')
        return result
    
    def writeline(self, text):
        """Write a string to the socket, followed by a newline"""
        self.client.send(text.strip().encode('utf8') + b'\n')
    

Note that I used a `b'...'` bytes literal to create a `bytes` object for the
newline to concatenate.

Here `writeline` encodes, so pass in _string objects_ when you call the
object:

    
    
    self.writeline('Ok, bye')
    

