Search code examples
pythonsocketsserverudpdelay

Python UDP socket; still receiving data when source is stopped; why?


I am sending 32 bytes packets every 1ms to this socket. I wish to print the data after every 40 ms. And apparently the code does that. But even when I stop sending data, I still continue to see that data is being printed. Is it holding the data in some cache? or simply the python socket has a huge delay? Why?

The code is as follows:

## Import necessary libraries
import math
import numpy as np
import socket
import struct
import time
from synchrophasor.frame import CommandFrame
from datetime import datetime


## Configure socket for Phasor data ##

UDP_IP = "10.10.114.22"
UDP_PORT = 8208 #UDP phasor values 32 bytes (V,phi,P)
sock_ph = socket.socket(socket.AF_INET,  # Internet
                     socket.SOCK_DGRAM)  # UDP
sock_ph.bind((UDP_IP, UDP_PORT))
print("socket bound, waiting for data...")


while True:

    raw = sock_ph.recv(32)
    #print(raw)
    mag = struct.unpack('d', raw[8:16])[0]
    # print("mag =",mag,type(mag))
    angle = struct.unpack('d', raw[16:24])[0]
    # print("angle =",angle,type(angle))
    header = struct.unpack('d', raw[0:8])[0]
    # print("header =",header,type(header))
    phasor = (mag, angle)
  
    Vol_A=raw
    VA = float(mag)
    phi_A = float(angle)
    VB = VA
    phi_B = phi_A+(math.pi) * 2 / 3
    VC = VA
    phi_C = phi_A-(math.pi) * 2 / 3
    time.sleep(1/25)
    # pmu.send_data(phasors=[(VA,phi_A),(VB,phi_B),(VC,phi_C)],analog=[9.91],digital=[0x0001])
    #time.sleep(1/config_rr)
    print([(VA,phi_A),(VB,phi_B),(VC,phi_C),datetime.now()])

Solution

  • most programs don't want to discard unread datagrams so most OSs will buffer them for you. your case is somewhat unusual so you'd need to write code to handle this case. I'd change your code to do something like:

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('', 8208))
    
    # block until we read an initial packet
    raw = s.recv(1024)
    s.setblocking(False)
    
    while True:
        # unpack
        header, mag, angle = struct.unpack('ddd', raw)
    
        # do something with data
        print(f'header={header} mag={mag} angle={angle}')
    
        # sleep for some time
        time.sleep(1/25)
    
        # discard any packets you've received in the mean time
        while True:
            try:
                raw = s.recv(1024)
            except OSError as err:
                # OS buffer is empty: we've therefore got the most recent data
                if err.errno == socket.EWOULDBLOCK:
                    break
                # something else failing, reraise the error
                raise
    

    note that Steffen Ullrich's suggestion of sending the data at the correct rate would be easier, but assumes that you have control over the sending process. the fact that you said "I am sending" suggests you do, and so would likely make a better solution