Python - Send and Receive of UDP packets - python

I've started with Python a few month ago. Now I've reached a point where I need some help concerning networking.
I've the following scenario:
One PC and 3 external devices in a small local net.
The PC wants to observe a switch state (on/off) on each device. This will be done by an initial command from the PC to each device.
After receiving this command each device sends automatically a packet with the new state to the PC whenever the switch state has changed.
All the packets on the network are UDP packets
On the PC I have the following Python script running (just for one device):
import socket
UDP_IP1 = "192.168.1.64"
UDP_IP2 = "192.168.1.73"
UDP_IP3 = "192.168.1.74"
UDP_PORT = 45 # used port on external device
port = 52129
message = "Message to observe..." # not the real command string
def SendData():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
msg = message.encode('utf-8')
s.sendto(msg, (UDP_IP1, UDP_PORT))
except:
print("Sending Error!!!\n")
return s
def ReceiveData(sock):
print("Receiving data: \n")
while True:
data, addr = sock.recvfrom(4096) # buffer size is 4096 bytes
print ("received message:", data)
if __name__ == "__main__":
s = SendData()
ReceiveData(s)
My Problem: In principal this script is running, but after approximately 2 minutes without any change of the switch on the device I do not receive any more packets from the external device when the switch state changes. But I can see the incoming packets with the installed Wireshark.
It looks like a time-out when I don't receive anything but 'sock.recvfrom' is still waiting for data.
Is there anyone who has/had the same problem?

Related

Python Socket Communicating Between PC and RPi

I am trying to make a small game and a part of it is to send a country name to Raspberry Pi from a laptop. Right now I am just sending a string, but later that string will be used to draw an image from a pen plotter attached to the RPi.
I am having trouble sending and receiving data using Python sockets (complete beginner). What I am trying to do is make the server keep sending the country name until the client receives it and then send a signal from the client back to the server that it has received the country name to make the server stop sending it and switch to listening mode. The client does some processing which right now is just print(f"Drawing country {country_name}") and then sends the server signal that it is finished.
Unfortunately both programs are running but nothing is happening. I am able to ping the laptop from RPi and vice versa. Furthermore the program in this link works for me:
Communication between two computers using python socket
My code for server side and client side is provided below:-
Server side (laptop)
#Import the necessary libraries
from socket import socket, gethostbyname, AF_INET, SOCK_DGRAM
import sys
import time
#Designate a port over which the communication will happen
PORT_NUMBER = 5000
#Protocol ?
SIZE = 1024
#Get the name of the host, this is our laptop
SERVER_NAME = gethostbyname('')
#Create the server socket, this is our laptop
Server_Socket = socket( AF_INET, SOCK_DGRAM )
Server_Socket.bind( (SERVER_NAME, PORT_NUMBER) )
#Set the client IP, this is our raspberry pi
CLIENT_IP = "192.168.88.244"
print ("Test server listening on port {0}\n".format(PORT_NUMBER))
#Create a variable that will become True if the client responds
client_response = False
#Start of while loop to keep sending data until client responds
while client_response == False:
#Create a delay so the client is not overwhelmed
time.sleep(3)
Server_Socket.sendto(b"Country_Name", (CLIENT_IP, PORT_NUMBER))
(client_response,addr) = Server_Socket.recvfrom(SIZE)
print(client_response)
#End of while loop to keep sending data until client responds
#Set client_response again to false
client_response = False
#Start of while loop to listen until client has done the task, this is our raspberry pi finishing the drawing
while client_response == False:
(client_response,addr) = Server_Socket.recvfrom(SIZE)
#End of while loop to listen until client has done the task, this is our raspberry pi finishing the drawing
#Close the server socket
Server_Socket.close()
print("Done")
sys.ext()
Client side (Raspberry Pi)
#Import the necessary libraries
from socket import socket, gethostbyname, AF_INET, SOCK_DGRAM
import sys
import time
#Set the server IP, this is our laptop
SERVER_IP = '192.168.88.250'
#Designate a port over which the communication will happen
PORT_NUMBER = 5000
#Protocol ?
SIZE = 1024
#Create the cleint socket, this is our raspberry pi
Client_Socket = socket( AF_INET, SOCK_DGRAM )
Client_Socket.bind( (SERVER_IP, PORT_NUMBER) )
#Set a variable that becomes True if the data sent by server is received
server_data_rcvd = False
#Start of while loop to listen until data from server is received
while server_data_rcvd == False:
#Create a delay so the client is not overwhelmed
time.sleep(1)
#Store country name
(country_name, addr) = Client_Socket.recv(size)
print("country_name")
#Start of if statement to check if country name is received
if type(country) == str:
server_data_rcvd = True
#Send response to the server
Client_Socket.sendto(True, (SERVER_IP, PORT_NUMBER))
#End of if statement to check if country name is received
#End of while loop to listen until data from server is received
#Draw the country
print(f"Drawing country {country_name}")
Client_Socket.sendto(True, (SERVER_IP, PORT_NUMBER))
#Close the socket
Client_Socket.close()
sys.exit()
What mistake am I making ? And how can I make the code more efficient and readable ?
Thanks in advance !
The client have to connect to the server with socket.connect, not socket.bind.
#Create the cleint socket, this is our raspberry pi
Client_Socket = socket( AF_INET, SOCK_DGRAM )
Client_Socket.connect( (SERVER_IP, PORT_NUMBER) )
There are a number of issues that could be causing your problem outside of the couple of typos (ex: size vs SIZE, country vs country_name, sys.ext vs sys.exit, etc).
UDP vs TCP
First off, you are using SOCK_DGRAM which suggests UDP as a protocol rather than TCP. This is fine as long as this is what you were expecting. UDP is connectionless where TCP requires your client to connect to your server.
Bytes
If you are using Python3, recv(buffersize[, flags]) -> data returns bytes, not a tuple of the data and an address. If you update that line to accept country, you'll then want to convert it to a string via country.decode('utf-8')
If you are using Python3, sendto(data[, flags], address) -> count expects data (not a boolean). What you can do is send bytes via b'True' or send 'True'.encode('utf-8').
Blocking recv
The biggest issue I see and probably what is causing you the most trouble is that your while loops are problematic. Not only does the while loop in your server never exit, but recv is a blocking action so if you were to start the server and then start your rpi, they will both be stuck at recv and neither will be sending. In your current setup, you have to launch rpi first so that it can listen, then start your server so it can send the country to the rpi. Otherwise, they are deadlocked since they are both listening for the other end to send something.

Python UDP socket.recv() stops recieving on Windows 10

I have a udp client function written in python running on Windows 10. I'm aware this is not production quality code but I'm only trying to grasp the fundamentals here
client = socket(AF_INET, SOCK_DGRAM)
client.bind(('192.168.0.107', CLIENT_PORT))
client.setblocking(False)
while True:
try:
data = client.recv( 1024 )
except:
continue
if data is not None:
print(data.decode('utf-8'))
I have a server running on an embedded device sending out small udp packets periodically (udp payload size of 22). This client gets about 10 of these packets give or take a few then the script stops receiving the udp packets. The only exception raised in the try/catch block is that there is no data to receive. If I change to blocking the behaviour is the same.
[WinError 10035] A non-blocking socket operation could not be completed immediately
The server is still sending the packets, I can see them in Wireshark with the expected IP addresses, ports, and verified checksums.
The thing is if I add a send after the receive stops the problem goes away entirely and I can continue receiving the udp payloads
client = socket(AF_INET, SOCK_DGRAM)
client.bind(('192.168.0.107', CLIENT_PORT))
client.setblocking(False)
while True:
try:
data = client.recv( 1024 )
except:
continue
if data is not None:
print(data.decode('utf-8'))
client.sendto("a_udp_payload".encode('utf-8'), ('192.168.0.108' , SERVER_PORT))
Is there something fundamental that I am missing here? Why does the stop working on the first snippet but not the second? Is there some buffer flushing issue?
Many thanks
Try to set timeout for the socket client.settimeout(2)

PC to raspberry Pi via TCP/IP socket

I am trying to do wireless communications between a PC (macbook) and a Raspberry Pi 2 using python's socket module (python 2.7). The server is the PC and the client is the Pi.
When I run the code (server first then client) both scripts get stuck on the socket.accept() and socket.connect() methods respectfully.
What is funny is that when I do the reverse (Pi being the server and PC being the client) the code works fine, with data been sent correctly.
The scripts below are meant to loop forever whilst incrementing a counter sent over (I increment the port's after each succesful transfer to avoid '[Errno 48] Address already in use' (probably terrible practice I know))
My client script:
import socket
import sys
def read(port):
s = socket.socket()
host = '10.19.92.44' #(IP address of PC (server))
s.connect((host,port))
try:
msg = s.recv(1024)
s.close()
except socket.error, msg:
sys.stderr.write('error %s'%msg[1])
s.close()
print 'close'
sys.exit(2)
return msg
if __name__ == '__main__':
port = 1025
while True:
print 'hey, checking TCP socket'
data = read(port)
print 'i just read %s' % data
print 'port num is: %d' % port
port = port + 1
My server script:
import socket
import time
def send(data, port):
s = socket.socket()
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print 'Got connection from',addr
c.send(data)
c.close()
if __name__ == '__main__':
port = 1025
num = 1
while True:
print 'hey, sending data'
words = 'helloWorld'
data = words + str(num)
print 'send data: %s' % data
send(data,port)
port = port + 1
num = num + 1
As I mentioned when I swap roles (and replace the server IP address in the client script to the Pis 172.17.33.125) the code works fine...
Any ideas/suggestions?
Thank you very much
I don't have an immediate answer, but I have a couple of ideas.
Your PC and Pi seem to be in different networks. The PC's address is 10.19.92.44, while Pi's is 172.17.33.125. There's a probability that 10.19.92.44 isn't the address you need. In order to find out what is the correct PC IP address to use in the application:
Issue networksetup -listallhardwareports to figure out the name of your wifi interface (should be like en0, en1).
Issue ifconfig, find the wifi interface. The IP address attached to this interface is the one you need.
Another option is to install wireshark on the PC, set up a working system (server-Pi, client-PC) and use wireshark to capture the traffic between the PC and Pi. Wireshark makes it easy to figure out IP addresses of both parties. I would advise to have this program installed whenever you want to debug a complicated networking issue.

Ensuring all the data gets received through UDP socket in Python

Possibly related questions that seem close but don't describe my issue as I understand it:
Reading all the data from a UDP socket
Python UDP socket semi-randomly failing to receive
Python raw socket listening for UDP packets; only half of the packets received
problem
Long file sent line by line doesn't go all the way through UDP over loopback.
long story
I have a long file consisting of lines and breaks that is identical to what I will get from another program over UDP locally. Let me emphasize that the program sending the packets will do so over UDP (there is no choice here), and cannot be feasibly modified to process ACK requests etc. while sending.
It looks like this (this is the tail):
StimulusTime 56398
Signal(0,2) -79.5457
Signal(0,4) -81.7426
Signal(0,6) -83.9978
Signal(0,9) -63.3755
Signal(0,11) -15.6045
Signal(0,13) 31.1299
Signal(0,16) 75.7539
Signal(0,18) 98.301
Signal(0,20) 98.301
Signal(0,22) 48.4546
Signal(0,25) 3.73159
Signal(0,27) -49.9798
Signal(0,29) -77.8449
Signal(1,0) -22.0332
Signal(1,2) -60.6384
Signal(1,4) -98.0858
Signal(1,6) -86.4579
Signal(1,9) -68.9173
Signal(1,11) -31.5552
Signal(1,13) 35.2906
Signal(1,16) 77.0686
Signal(1,18) 96.3836
Signal(1,20) 95.7246
Signal(1,23) 25.6074
Signal(1,25) -20.2101
Signal(1,27) -60.2933
Signal(1,29) -83.8169
Signal(2,0) -31.8826
Signal(2,2) -53.5045
Signal(2,4) -89.9895
Signal(2,7) -84.4503
Signal(2,9) -59.7016
Signal(2,11) -12.8569
Signal(2,13) 28.857
Signal(2,15) 58.0577
Signal(2,18) 96.4222
Signal(2,20) 79.783
Signal(2,22) 58.6463
Signal(2,25) -3.24883
Signal(2,27) -45.5
Signal(2,29) -88.8937
Signal(3,0) -18.6625
Signal(3,2) -53.3978
Signal(1,16) 58.784
Signal(1,17) 44.7782
Signal(1,18) 6.247
Signal(1,19) -12.0855
Signal(1,20) -33.7644
Signal(1,21) -49.4406
Signal(1,22) -67.5791
Signal(1,23) -92.0336
Signal(1,24) -93.9841
END
I wrote code that takes this file and sends it a line at a time over UDP locally, and then code that receives it and parses it based on the data type.
Sender:
import socket
import sys
# Sends udp test data piped in from STDIN to the listener.
# ex: cat sampleoutput.txt | python testsender.py
UDP_IP = "127.0.0.1"
UDP_PORT = 5000
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
# Send from stdin
if len(sys.argv) < 2:
while True:
line = sys.stdin.readline()
if line:
sock.sendto(line, (UDP_IP, UDP_PORT))
else:
break
# get from file arg
else:
myfile = open(str(sys.argv[1]), "r")
while True:
line = myfile.readline()
if line:
sock.sendto(line, (UDP_IP, UDP_PORT))
else:
break
sock.close()
Listener:
import socket
from array import array
UDP_IP = "127.0.0.1"
UDP_PORT = 5000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size arg
print data
# write to file for later testing
# file = open("testdummy.txt", "a")
# file.write(data)
if data == "END\n":
break
I was able to use the above listener to produce the test file from the original program, so it should work. Unfortunately, it fails around 500 lines of payload, as tested by tail -n 500 testdummy.txt | python testsender.py, although it's somewhat random. Specifically, the listener does not receive all of the sent lines before the sender exits, leaving it hanging, waiting for the "END\n" string.
As I understand it, the socket is already in blocking mode--how can I prevent this from occurring?
My first advice to you, Don't use UDP if you want to transfer files with the sequence of lines preserved, Use TCP if you don't want to code alot. The reasons are;
UDP is an unreliable Protocol, in the sense a Packet sent is not guaranteed to be received by the recipient.
UDP doesn't guarantee the sequence of packets being received, This is because UDP packets may go to recipient via several routes (Hops between computers). So latter sent packets can take a short route and reach the recipient before former sent packets. ("End\n" packet can come before other packets)
TCP on the other hand is reliable and sequence of packets received is guaranteed. Ideal for file transfer.
But don't worry File sharing applications like Bear Share, Bit Torrents make use of UDP but there are some additional coding you have to do.
You need to implement an Acknowledgement protocol, as in you need to have a unique id for each packet you send to the recipient and when the packet is received recipient should send an Acknowledgement packet back to the sender with that id saying the packet was received.
If in case the packet got lost and didn't reach the recipient (No Acknowledgement from recipient) you must resend the packet again (and again) until you get the Acknowledgement.
You can control the order by not sending the next packet until you get the Acknowledgement for the previous one.

networking program crashes

i got this code from http://www.evolt.org/node/60276 and modified it to listen for a single "1" coming from the other side
but whenever i run this program it stops and python IDLE goes to non-responding on "data1,addr = UDPSock.recvfrom(1024)"
def get1():
# Server program, receives 1 if ball found
# ff1 is file w/ received data
import socket
import time
# Set the socket parameters
host = "mysystem"
port = 21567
#buf = 1024
addr = (host,port)
# Create socket (UDP) and bind to address
UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
UDPSock.bind(addr)
# Receive messages
while 1:
print "waiting..............."
data1,addr = UDPSock.recvfrom(1024)
print "got 1"
if not data1:
print "Client has exited!"
break
else:
print "\nReceived message '", data1,"'"
UDPSock.close() # Close socket
print "socket closed\n"
#call some other function that uses 1
and client side
def send1():
# Client program, sends 1 if ball found
# mf1 is file with data to be sent
import socket
# Set the socket parameters
host = "mysystem"
port = 21567
buf = 1024
addr = (host,port)
# Create socket (UDP)
UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
mf1=1
print mf1
# Send messages
if(UDPSock.sendto(str(mf1),addr)):
print "Sending message '",str(mf1),"'....."
# Close socket
UDPSock.close()
does anyone know what might be the cause of this? (sorry for long post)
As a second guess (I replaced my first guess with this) I suspect that you are running the receiver in IDLE and then IDLE is hanging so you can't run the client. I don't know exactly how IDLE works as I never use it, but the line containing recvfrom will stop the Python thread its running in until data is sent. So you need to start the client in a separate instance of IDLE or from the command line or something.
At any rate, I have tested the program in question on my Python with 127.0.0.1 as the host, and it worked fine, for some values of fine. The recvfrom does hang, but only until some data is sent, then it comes back with the data and prints it out and everything. You do have a bug that happens after that though. :-)

Categories