Reputation:
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
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