I've been writing and maintaining a personal use utility that pings 8.8.8.8
every 1s and displays a pip indicating the network's condition for a while now, and due to the fact that my network appears to have inherent ~1.7% packet drop, I made it run two PING.EXE processes in parallel, with a timeout of 950ms so as to differentiate between randomly dropped packets and brief outages(these also happen)
Now, the problem is: I don't have enough control over the pings, and I've run into issues with the fact that PING.EXE's delay of 1s is not exact enough, and as the processes drift, I randomly get heavily degenerate cases like 60 pips correlating to 107.24s instead of the intended 60s.
I could probably work around this issue by launching a new ping process every second, but that's an extremely inelegant solution, and with non-negligible overhead(on Windows at least) besides, and I'd like to refrain from needing to manually send ICMP packets because then I'd need to run my utility with administrative privileges.
Apologies for the open-ended "is there anything" question, but without knowing anything, I don't know what to ask for.
EDIT: I've tried lowering the timeout from 999ms to 900ms and even 750ms, but PING.EXE either does not adhere to it, or it does so improperly, because this keeps happening, although the issue is much smaller - +15s under maximum network load. Probably acceptable enough, but...
If you need to replicate ping
exactly in Python, you would need administrator privileges to send ICMP packets to a host.
You could instead rely on TCP packets and tap the http port. That does not require admin privileges. Neither is it quite as accurate but it is an more accurate portrayal of web browsing ability.
Simplifying this TCP ping code:
import sys
import socket
import time
import signal
from timeit import default_timer as timer
host = "google.com"
port = 80
# Default to 10000 connections max
maxCount = 10000
count = 0
# Pass/Fail counters
passed = 0
failed = 0
def getResults():
""" Summarize Results """
lRate = 0
if failed != 0:
lRate = failed / (count) * 100
lRate = "%.2f" % lRate
print("\nTCP Ping Results: Connections (Total/Pass/Fail): [{:}/{:}/{:}] (Failed: {:}%)".format((count), passed, failed, str(lRate)))
def signal_handler(signal, frame):
""" Catch Ctrl-C and Exit """
getResults()
sys.exit(0)
# Register SIGINT Handler
signal.signal(signal.SIGINT, signal_handler)
# Loop while less than max count or until Ctrl-C caught
while count < maxCount:
# Increment Counter
count += 1
success = False
# New Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 1sec Timeout
s.settimeout(1)
# Start a timer
s_start = timer()
# Try to Connect
try:
s.connect((host, int(port)))
s.shutdown(socket.SHUT_RD)
success = True
# Connection Timed Out
except socket.timeout:
print("Connection timed out!")
failed += 1
except OSError as e:
print("OS Error:", e)
failed += 1
# Stop Timer
s_stop = timer()
s_runtime = "%.2f" % (1000 * (s_stop - s_start))
if success:
print("Connected to %s[%s]: tcp_seq=%s time=%s ms" % (host, port, (count-1), s_runtime))
passed += 1
# Sleep for 1sec
if count < maxCount:
time.sleep(1)
# Output Results if maxCount reached
getResults()
Once you can create a 'ping' you could encapsulate the result of each time / ping result into an object stream to display as you wish.