I just learned about #python recently, I have done a small project about rasberry pi. I want to transmit and receive data between Server is Laptop, client is Ras via UDP protocol, I use Python’s socket library. Transmit sensor data from ras to laptop, and transmit control commands from laptop to ras. Data from ras must always be transmitted, so I used a while true loop with time.sleep. The problem is again at this point, the control command from the laptop is not always sent, only sent when necessary, I receive the control command on Ras by recvfrom() is also in the while True loop, so when not transmitting the control command is the while true loop stuck here, so the data from the sensor cannot be transmitted anymore. m.n help me give advice or keywords for this article. Thank you.
server.py
import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ip = "" port = 5001 server_address = (ip, port) s.bind(server_address) while True: print("####### Server is listening #######") data, address = s.recvfrom(4096) print("nn 2. Server received: ", data.decode('utf-8'), "nn") s.sendto(send_data.encode('utf-8'), address) print("nn 1. Server sent : ", send_data, "nn") time.sleep(1)
cilent.py
import time import socket import random UDP_IP = "" UDP_PORT = 5001 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM, 0) while True: roll = random.randrange(1,100) a = str(roll) s.sendto(a.encode('utf-8'), (UDP_IP, UDP_PORT)) print("data gui:",str(roll).encode('utf-8')) data, address = s.recvfrom(4096) print("data nhan",data) time.sleep(1)
Advertisement
Answer
If the sending of the data from the RasPi to the PC is a fairly independent thing that must always run, you could consider making a separate thread of execution for it so you can sleep()
in there and generally do whatever you want without interfering with receiving occasional commands that you must respond to. There’s a great description of threads here but it might look like this:
#!/usr/bin/env python3 import sys import time import random import logging import threading, queue def Transmitter(): """Transmits readings to PC at 1 second intervals on a separate thread""" logging.debug(f'[Transmitter] Starting') # Start independent loop sending values i = 0 while True: reading = random.randint(0,100) logging.debug(f'[Transmitter] Iteration: {i}, reading: {reading}') i += 1 time.sleep(1) if __name__ == '__main__': # Set up logging - very advisable with threaded code logging.basicConfig(level=logging.DEBUG, format='%(levelname)s %(message)s') # Create independent thread to transmit readings thr = threading.Thread(target=Transmitter, args=()) thr.start() # Main loop - waiting for commands from PC logging.debug('[Main] Starting main loop') i = 0 while True: # Not what you want but just showing the other thread is unaffacted by sleeping here time.sleep(5) i += 1 logging.debug(f'[Main] Iteration: {i}')
Here’s the output from a sample run:
DEBUG [Transmitter] Starting DEBUG [Transmitter] Iteration: 0, reading: 82 DEBUG [Main] Starting main loop DEBUG [Transmitter] Iteration: 1, reading: 84 DEBUG [Transmitter] Iteration: 2, reading: 45 DEBUG [Transmitter] Iteration: 3, reading: 47 DEBUG [Transmitter] Iteration: 4, reading: 97 DEBUG [Main] Iteration: 1 DEBUG [Transmitter] Iteration: 5, reading: 81 DEBUG [Transmitter] Iteration: 6, reading: 20 DEBUG [Transmitter] Iteration: 7, reading: 6 DEBUG [Transmitter] Iteration: 8, reading: 16 DEBUG [Transmitter] Iteration: 9, reading: 54 DEBUG [Main] Iteration: 2 DEBUG [Transmitter] Iteration: 10, reading: 67 DEBUG [Transmitter] Iteration: 11, reading: 91 DEBUG [Transmitter] Iteration: 12, reading: 37
Likewise, if you don’t want to hang/block on the RasPi waiting for commands from the PC, you could start another thread that sits in a tight loop, doing blocking reads from the UDP command port. It could then put the commands into a Python Queue
for the main program to read whenever it wants, and it can do the read with a timeout which means the main thread doesn’t block when there are no incoming commands. Good description here, but the code might look something like this:
#!/usr/bin/env python3 import sys import time import random import logging import threading, queue def Transmitter(): """Transmits readings to PC at 1 second intervals""" logging.debug(f'[Transmitter] Starting') # Start independent loop sending values i = 0 while True: reading = random.randint(0,100) logging.debug(f'[Transmitter] Iteration: {i}, reading: {reading}') i += 1 time.sleep(1) def Receiver(Q): """Waits for commands and queues them to the main process""" logging.debug(f'[Receiver] Starting') # Wait for commands from PC and place into queue while True: # We will actually wait a random number of seconds and then synthesize dummy command time.sleep(random.randint(3,7)) cmd = f'command_{random.randint(100,200)}' logging.debug(f'[Receiver] Synthesizing cmd: {cmd}') Q.put(cmd) if __name__ == '__main__': # Set up logging - very advisable with threaded code logging.basicConfig(level=logging.DEBUG, format='%(levelname)s %(message)s') # Create independent thread to transmit readings tx = threading.Thread(target=Transmitter, args=()) tx.start() # Create independent thread to receive commands and send to us via queue Q = queue.Queue() rx = threading.Thread(target=Receiver, args=(Q,)) rx.start() # Main loop - processing commands from queue logging.debug('[Main] Starting main loop') msgNum = 0 while True: # Wait for a message from queue... # ... you can either block like I am here # ... or use timeout and not block cmd = Q.get() msgNum += 1 logging.debug(f'[Main] Received cmd: {cmd} {msgNum}')
Note: I don’t believe Python sockets are thread-safe, so you would probably want to send and receive on different ports with this approach – but that shouldn’t be a problem as there are 65,000 ports.