1

I'm making a simple Python application which will allow people to communicate with each other through a CLI. I am relatively new to the sockets module, however my code has no problems. Except for one. When I run my two scripts (chatclient.py and chatserver.py), they run fine. The server starts up, and the client will ask the user for their name and the message. However upon clicking enter to send the message, i receive:

TypeError: decoding str not supported

I have tried using .encode('utf-8)/ .decode('utf-8') but still the same error. The code will be below (with multi comments around the 'wrong' code).

#client.py
import socket
import threading
import time

tLock = threading.Lock()    #creates a lock for the thread and prevents output to the screen
shutdown = False

def receiving(name, sock):
    while not shutdown: #while the program is still running
        try:
            tLock.acquire() #acquires the lock
            while True:
                data, addr = sock.recv(1024).decode('utf-8')    #gets the data and address from the data received
                print(str(data))
        except:
            pass

        finally:
            tLock.release() #releases the lock

host = "127.0.0.1"  #uses localhost as the host
port = 0 #picks up any free port on the computer

server = ("127.0.0.1",5000)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
s.setblocking(0)

rt = threading.Thread(target=receiving, args=("RecvThread", s))
rt.start()

'''name = input("Enter your name: ")
message = input("> ")
while message != "q":
    if message != '':
        print("From ",name)
        s.sendto(str(name, message), (host,port)).decode('utf-8')'''

    tLock.acquire()
    message = input('')
    tLock.release()
    time.sleep(0.5)

shutdown = True
rt.join()
s.close()

^^^client

#server.py
import socket
import time

host = "127.0.0.1"   #makes localhost the host server
port = 5000          #uses any random port between 1024 and 65535

clients = []

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    #creates a new socket object
s.bind((host,port))   #binds the host and port to socket object
s.setblocking(0)      #sets the blocking to 0 (essentially no blocking)

quitting = False
print("The server has now started on ",time.ctime(time.time()))

while not quitting: #while quitting hasn't happened
    try:
        data, addr = s.recvfrom(1024).decode('utf-8') #tries to get data and address from the data coming in
        if "Quit" in data: #if the data has quit in it
            quitting = True #quitting = true meaning the while not quitting loop would break
        if addr not in clients: #if the address given is not in the list 'Clients' 
            clients.append(addr)  #then it will append it to the list

        print(time.ctime(time.time()),"- ",str(addr).decode('utf-8')," : ",str(data).decode('utf-8'))   #prints the time, the address and the message

        for client in clients:  #for each client in the list of clients
            s.sendto(bytes(data, 'utf-8'))   #send the data to the clients
            s.sendto(bytes(client, 'utf-8'))

    except:
        pass

s.close()

^^^server

1
  • There's no 'decode' method for strings in Python 3 as strings are now unicode strings. You can decode bytes object (e.g. result of bytes(blah) or "blah".encode()). Commented Feb 26, 2017 at 11:05

1 Answer 1

1

If you pass 2 or more values to str, it tries to decode, but in your case, the first argument is already string object (because the return value of input function is string); causes the error.

>>> str('a')
'a'
>>> str('a', 'utf-8')   # trying to decode (the 2nd arg. is encoding)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: decoding str is not supported
>>> str(b'a', 'utf-8')
'a'

Beside that, you need to pass bytes object to socket.sendto as the first argument. Encode string to get a bytes object:

>>> 'a'.encode()  # You can omit encoding arg.; `utf-8` is default in Python 3.x
b'a'
>>> 'a'.encode('utf-8')
b'a'

Replace following line of client code:

s.sendto(str(name, message), (host,port)).decode('utf-8')

with:

s.sendto('{}: {}'.format(name, message).encode('utf-8'), (host,port))

data, addr = s.recvfrom(1024).decode('utf-8')

Above line is also wrong. socket.recvfrom(..) returns a tuple of (message, address). The tuple does not have decode method. You need to decode message only.

data, addr = s.recvfrom(1024)
data = data.decode('utf-8')

server

import socket
import time

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 5000))

print("The server has now started on ", time.ctime())

clients = []
while True:
    data, addr = s.recvfrom(1024)
    text = data.decode('utf-8')
    if "Quit" in text:
        break

    if addr not in clients:
        clients.append(addr)

    print(time.ctime(), "-", addr, ":", text)
    for client in clients:
        s.sendto(data, client)

s.close()
Sign up to request clarification or add additional context in comments.

5 Comments

the error has gone, but im not receiving any mesages. I have opened to terminal tabs running the code however once i enter my name and message, the client just says from name: and nothing else? Would you happen to know why?
@ELiTEMagiK, Server code has big try: ... except: pass block. It will shadow all exceptions. Try to remove it, and run it. You will see what's the problem. Advice: Do not catch all exception, but specific one; and handle the exception. Just pass is not a good practice.
@ELiTEMagiK, Another issue: The client is sending to (host, port) where port = 0. You should use server variable you defined instead of (host, port) which is used to bind client socket. BTW, you don't need to bind client socket.
@ELiTEMagiK, I added corrected server code to the answer.
@ELiTEMagiK, That's why I added s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) in the server code. Please google for SO_REUSEADDR. Also make sure the client is not bound to 127.0.0.1:5000. (As I commented before, you don't need bind client socket manually, it's done by kernel automatically)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.