user6471770
user6471770

Reputation:

Python3 Socket Module: decoding str

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

Upvotes: 1

Views: 12338

Answers (1)

falsetru
falsetru

Reputation: 369074

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()

Upvotes: 1

Related Questions