Encoding problem when printing message in UDP client-server using Python - python

I am trying to create a UDP client-server from a TCP one. I ran into an issue with encoding and printing my receiving message from the server to the client. It works the way I have it on TCP but doesn't seem to work on UDP and I am not sure on what else I have to encode?
Here is the error I am getting:
File "/Users/PycharmProjects/UDPProject/client.py", line 29, in <module>
print("received %s" % command)
TypeError: not all arguments converted during string formatting
And here is my client code with some code cut out.
while True:
message = input("Please enter a command:\n") # ask user to input message
if message == 'quit':
break
if len(message) == 0:
print("Please enter something")
message = input("Please enter a command:\n")
print("Sending %s" % message)
sock.sendto((message.encode("utf-8")), address) # send message
command = str(sock.recvfrom(BUFFER_SIZE), "utf-8")
print("received %s" % command)
print("closing connection with server")
sock.close()
It is happening when the socket is trying to receive from the buffer size in utf-8 format and when I try to print it.
EDIT: I fixed the error, it was just typo as outlined by lenz but now it gives me this error
command = str(sock.recvfrom(BUFFER_SIZE), "utf-8")
TypeError: decoding to str: need a bytes-like object, tuple found
I am not sure why???

socket.recvfrom returns a tuple of pair (bytes, address) in UDP so I had to decode the first item of bytes. This is how I did it.
command = str(sock.recvfrom(BUFFER_SIZE)[0], "utf-8"). The [0] grabs the first item in the tuple of BUFFER_SIZE

Related

Python HL7 Listener socket message acknowledgement

I am trying to create HL7 listener in python. I am able to receive the messages through socket , but not able to send valid acknowledgement
ack=u"\x0b MSH|^~\\&|HL7Listener|HL7Listener|SOMEAPP|SOMEAPP|20198151353||ACK^A08||T|2.3\x1c\x0d MSA|AA|153681279959711 \x1c\x0d"
ack = "MSH|^~\&|HL7Listener|HL7Listener|SOMEAPP|SOMEAPP|20198151353||ACK^A08||T|2.3 \r MSA|AA|678888295637322 \r"
ack= bytes(ack,'utf-8')
Python code :
def listner_hl7():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((socket.gethostname(), 4444))
except Exception as e:
print(str(e))
s.listen(5)
while True:
clientSocket, addr = s.accept()
message = clientSocket.recv(2048)
id = (str(message.splitlines()[0]).split('|')[9])
print('received {} bytes from {}'.format(
len(message), addr))
print('sending acknowledgement: ')
ack = b"\x0b MSH|^~\\&|HL7Listener|HL7Listener|SOMEAPP|SOMEAPP|20198151353||ACK^A08||T|2.3\x1c\x0d MSA|AA|" + bytes(
id, 'utf-8') + b" \x1c\x0d"
clientSocket.send(ack)
I think your complete acknowledge is not being sent. You are using clientSocket.send(ack).
Use clientSocket.sendall(ack) instead.
Please refer to this answer from #kwarunek for more details.
socket.send is a low-level method and basically just the C/syscall method send(3) / send(2). It can send less bytes than you requested, but returns the number of bytes sent.
socket.sendall is a high-level Python-only method that sends the entire buffer you pass or throws an exception. It does that by calling socket.send until everything has been sent or an error occurs.
If you're using TCP with blocking sockets and don't want to be bothered by internals (this is the case for most simple network applications), use sendall.
try adding enter in front of MSA|AA in the \n syntax I think it works

TypeError: a bytes-like object is required, not 'str' when writing to a file

import socket
def Main():
host = '127.0.0.1'
port = 5001
server = ('127.0.0.1',5000)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
message = input("-> ")
while message != 'q':
s.sendto (message, server)
data, addr = s.recvfrom(1024)
print ('Received from server: ' + (data))
message = input("-> ")
s.close()
if __name__ == '__main__':
Main()
When I run this code the line s.sendto (message, server) causes a TypeError: a bytes-like object is required, not 'str'.
How do you fix this kind of problem? I tried searching the internet but can't find a solution.
Sockets read and write bytes, not strings (that's a property of sockets in general, not a python-specific implementaiton choice). That's the reason for the error.
Strings have an encode() methods that transforms them to byte-objects. So, instead of writing my_text, write my_text.encode() to your socket.
Similarly, when you read for the socket, you get a bytes-like object, on which you can call input_message.decode() to convert it into string
The error is due to the fact you are not encoding the message.
Just change:
c.sendto(message, server)
to
c.sendto(message.encode(), server)
in your code.
Example:
import socket
s=socket.socket()
port=12345
s.bind(('',port))
print("Socket bind succesfully")
s.listen(5)
// note this point
message="This is message send to client "
while True:
c,addr=s.accept()
// here is error occured
c.send(message)
c.close()
This is will result in an error message:
c.send(message)
TypeError: a bytes-like object is required, not 'str'
and in order to fix it, we need to change:
c.send(message)
to
c.send(message.encode())

Using socket code and changing it to python 3.5.0 and getting TypeError: a bytes-like object is required, not 'str' error

Got code from http://www.binarytides.com/python-socket-programming-tutorial/ and changed it to work in python 3.5. It looks like this:
#Socket client example in python
import socket #for sockets
import sys #for exit
#create an INET, STREAMing socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print ('Failed to create socket')
sys.exit()
print ('Socket Created')
host = 'www.google.com';
port = 80;
try:
remote_ip = socket.gethostbyname( host )
except socket.gaierror:
#could not resolve
print ('Hostname could not be resolved. Exiting')
sys.exit()
#Connect to remote server
s.connect((remote_ip , port))
print ('Socket Connected to ' + host + ' on ip ' + remote_ip)
#Send some data to remote server
message = ("GET / HTTP/1.1\r\n\r\n")
try :
#Set the whole string
s.sendall(str(message))
except socket.error:
#Send failed
print ('Send failed')
sys.exit()
print ('Message send successfully')
#Now receive data
reply = s.recv(4096)
print (reply)
and the shell is giving the error "TypeError: a bytes-like object is required, not 'str'" on line 36 where the code is s.sendall(str(message)). Since I'm trying to get into socket programming for a school project I'm really not sure what the error means and haven't found a good example of how to solve it.
The socket().sendall method expects a "bytes-like object", which means a bytes object (or a bunch of other types like memoryview). You are passing a str object, which represents a unicode string, to that method.
To fix this error, you need to encode your message with message.encode(<encoding>) or bytes(message,<encoding>).

Send and receive to/from a UDP socket python3.4

i have these lines of code for sending and receving from a UDP socket in python3.4, in which i want to send a file from a user to the other.
This is the server side code:
...
data = file.read(1024)
n = int(fileSize / 1024) + 1
for i in range(n):
if(self.sock.sendto(data.encode(), ('127.0.0.1',int(self.nextUserPort)))):
print ("Sending ...")
data = file.read(1024)
print ("File has been Sent Completely!!!")
self.sock.sendto("END#".encode(), ('127.0.0.1',int(self.nextUserPort)))
And this is the client side code:
....
d = self.sock.recvfrom(1024)
data = d[0].decode()
addr = d[1]
try:
while (data.strip().find("END#") != 0) :
file.write(data.decode())
time1 = time.time()
data, addr = self.sock.recvfrom(1024)
time2 = time.time()
print ("download speed is "+ str(1.0/(time2-time1))+" kbps")
print ("File Downloaded Completely!!!!!")
except socket.timeout :
file.close()
self.sock.close()
But when i run the code i get the below error for the line f(self.sock.sendto(data.encode(), ('127.0.0.1',int(self.nextUserPort)))):
AttributeError: 'bytes' object has no attribute 'encode'
And when i remove the encode i get another error that when i searched it i got that i must encode it in python3.4.
The exception is telling you what the problem is:
AttributeError: 'bytes' object has no attribute 'encode'
And as it happens you want to send bytes, so no need to convert anything in this line.
"END#".encode() can be directly written as b"END#".
Unrelated to your question: You might want use a TCP socket or give the transfer some logic to cope with reordered, lost and duplicated packages.

Python: socket.recv() doesn't receive push messages

Python: socket.recv() doesn't receive push messages
Hello,
I'm coding a socket based IMAP client in Python3 which successfully establishes a connection to the server, succussfully transmits the IDLE command but then fails to receive incoming data from the server.
If you are wondering why I do not use libimap or sth., the answer is easy: I just want to implement an IDLE command-supporting python client which must be written without that library.
An extract:
import socket
def runIMAPPeek():
#socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(29 * 60)
#connection
s.connect((IMAP_SERVER , 443))
#login
data = b"a1 LOGIN " + USER + b" " + PASSWORD + b"\n"
s.sendall(data)
reply = read(s)
#Idle loop
#As in RFC 3501 connection will be reinitialized every 29 minutes
while True:
# Idle command
print("#Sending IDLE...")
data = b"a2 IDLE\n"
s.sendall(data)
reply = read(s)
if reply.startswith("+ idling"):
print(" #idling.")
else:
print(" #Unexpected answer: {}".format(reply))
#sys.exit()
# waiting for incoming mails ----------------------------------
try:
push_msg = read(s)
# got push message = new message arrived
getNewEnvelope(s, push_msg)
except socket.timeout:
# timeout
print(" #timeout. Reinitializing IDLE...")
#TODO: except (KeyboardInterrupt, SystemExit)
# Quit Idle
data = b"DONE\n"
write(s, data)
reply = read(s)
if reply.startswith(prefix_str + " OK"):
print(" #quit idling.")
else:
print(" #Unexpected answer: {}".format(reply))
#sys.exit()
def read(s):
"""Read socket data, print it, convert to string, replace new lines
and return it.
"""
print("#Receiving...", end=" ")
reply = s.recv(4096)
reply = str(reply)[2:-1] #convert and remove byte indicators
reply = reply.replace("\\r\\n", "\n")
print(reply)
return reply
The problem is marked with the "----". Although messages are received in the mailbox, python does not react but remains in the idling/receiving state. In fact, the print line above the s.recv() command isn't even printed.
I tried everything successfully with Telnet, so there is no server problem.
In addition to my comment above, you have never selected INBOX. You will not receive any push messages, because you haven't told it what folder you want. Technically, IDLE is not valid in the unselected state.
Constructs like this one:
if reply.startswith("+ idling"):
are completely non-compliant. The IDLE RFC specifies that the client shall expect a continuation request, not this particular string (which also happens to be a continuation request).

Categories