6 svar
95 visningar
poopfeast420 behöver inte mer hjälp
poopfeast420 5
Postad: 16 mar 2022 14:33

Nätverksrelaterad programmeringsfråga

Jag har ett Pythonprogram där jag bygger en ethernet-header med scapy:


frame = (Ether(dst='2c:44:fd:10:32:a1',src='b8:27:eb:95:42:a2') 
/ Dot1Q(vlan=1) 
/ Dot1Q(prio=7) 
/ IP(dst='192.168.4.100',src='192.168.4.200') 
/ ICMP()) 
  
Sen så har jag en loop för att sända datan periodiskt i en sekund i taget.

q = datetime.now() 
p = datetime.now() 
i=0 
while True: 
    while p < q: 
        p = datetime.now() 
    sendp(frame, iface='eth0') 
    q += timedelta(seconds = 1) 
    i+=1 
    print("Sending packet #%d ST: %s" %(i,str(p)))


Sen loggar jag i Wireshark när paketen kommer. Jag gör även så scriptet får högsta prio i Linux.

Problemet är att scriptet producerar ett jitter på ca 50ms beroende på när paketen skickas av Python. Jag behöver ha ner det här jittret så paketen skickas så nära sitt schema som möjligt och jag har inga bra idéer.

För att tydliggöra så kanske paket 1 skickas på exakt 0.000s vilket är bra, paket två på 0.98s, paket tre på 2,04. Vilket har resulterat i ett jitter på 60ms. Jag behöver ha de här värdena mycket mer exakt. Helst ner på mikrosekunder.

Jag har hört ordet interrupts. Men jag vet inte riktigt vad det är eller hur man använder det.

Källkod finns här för den som vill testa. https://easyupload.io/03yb8q

Mega7853 211
Postad: 16 mar 2022 15:16

Jag skulle tro att time.time() har mindre jitter än datetime.now(). time.time() returnerar en float med sekunder, så den gör inte lika mycket beräkningar. Ytterligare bättre är kanske att använda time.sleep() istället för en while-loop.

Det finns ett bibliotek som gör detta åt dig, sched. Jag hittade detta exemplet, men jag gissar på att enterabs() kan ge ännu bättre noggrannhet. Se nästa kod-snutt.

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    print("Doing stuff...")
    # do your stuff
    s.enter(1, 1, do_something, (sc,))

s.enter(1, 1, do_something, (s,))
s.run()

Detta är otestat, men enterabs() sätter en exakt tid istället för enter() som lägger till en delay relativt när du råkade köra enter().

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    s.enterabs(time.time()+1, 1, do_something, (sc,))
    print("Doing stuff...")
    # do your stuff

s.enter(1, 1, do_something, (s,))
s.run()

Det är tydligen också så att time.time() har en noggrannhet på 16ms på Windows, så det blir inte bättre än så.

Mega7853 211
Postad: 16 mar 2022 15:30

Jag inser nu att mitt andra exempel inte gör någon förbättring.

Återigen, helt otestat, men det kan fungera att ha en global variabel "tid" som sätts till time.time()+1, som ökas med 1 inuti do_something() och används i enterabs().

Ännu mindre beräkningar sker om man använder time.time_ns() så det borde ge ännu mindre jitter.

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    nonlocal tid
    print("Doing stuff...")
    # do your stuff
    tid+=1
    s.enterabs(tid, 1, do_something, (sc,))

tid=time.time()+1
s.enterabs(tid, 1, do_something, (s,))
s.run()
Laguna Online 30704
Postad: 16 mar 2022 16:21

Det är nog olämpligt att göra print också.

Vad är det för operativsystem? Det kanske är möjligt att göra så noggranna saker i python, men det kan vara själva operativsystemet som fördelar tiden mellan processerna så att noggrannheten inte blir bättre. I så fall kan man kanske ordna så att man får högre prioritet för just den här processen.

poopfeast420 5
Postad: 16 mar 2022 16:24
Laguna skrev:

Det är nog olämpligt att göra print också.

Vad är det för operativsystem? Det kanske är möjligt att göra så noggranna saker i python, men det kan vara själva operativsystemet som fördelar tiden mellan processerna så att noggrannheten inte blir bättre. I så fall kan man kanske ordna så att man får högre prioritet för just den här processen.

Tack för alla svar @Mega7583 och Laguna. Jag kör det här på en Raspberry Pi 3b. Scriptet drar upp prion på processen till den högsta.

Jag pasteade ett äldre script och jag använder time.time och har stängt av print-satsen. Jag ska testa det senare alternativet som Mega nämnde.

Återkommer.

Mega7853 211
Postad: 16 mar 2022 16:24

Många svar nu... :-)

Jag ser ingen skillnad på jitter när jag kör min och din kod (utan sendp!). Jag får <1ms på båda på min linux-maskin.

Kanske ligger problemet istället i sendp(). Det kan ju hända ganska mycket i en sådan funktion på väg ner till hårdvaran.

poopfeast420 5
Postad: 16 mar 2022 16:47
Mega7853 skrev:

Många svar nu... :-)

Jag ser ingen skillnad på jitter när jag kör min och din kod (utan sendp!). Jag får <1ms på båda på min linux-maskin.

Kanske ligger problemet istället i sendp(). Det kan ju hända ganska mycket i en sådan funktion på väg ner till hårdvaran.

Tror nog tyvärr du har rätt. Jag körde din kod nu och fick jitter.

Testade att printa time.time före och efter sendp(). Värdena före sendp() var jitter-fria och de efter hade jitter.

Fakk.

Men då har ni hjälpt mig att identifiera boven, och det tackar jag för.

Svara
Close