Python 2.7 simple packet sniffer - python

I wrote simple packet sniffer in Python. I need to receive packets non-stop and send one packet every 10 seconds. I tried this:
current = time.time()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("xx.xx.xx.xx",xxxx))
time.sleep(0.5)
while True:
msg = str(s.recv(4096))
time.sleep(0.010)
print msg
if current==current+10:
s.send("<myPacket/>")
current = time.time()
but it doesn't work good. Anyone have better idea?

Your time handling is bad, use this instead:
While True:
...
time.sleep(10)
Your code doesn't work because:
'current' can never be equal to itself+10.
Also note that time.time() returns a float value e.g: 1440185304.78
which is very accurate to that exact moment, you should never assume you can find that exact float +10 back.
Using a larger/smaller statement is better in this case since the exact value might have passed while your loop is running whatever is in it, e.g:
t = time.time()
while True:
while time.time() < t + 10:
time.sleep(0.1)
t = time.time()
print ("hi")

Related

bind takes a long time

I am using over 20 raspberry pis to control heating and other functions in my house. For instance each room has a pi (client) with a temperature sensor, which sends a message to another pi (server) at one of three manifolds to open or close a valve on the heating system.
My problem is the amount of time the server takes to execute the bind instruction. A newly set up pi will typically take a few millisecond to execute the line, but soon the time becomes variable, sometimes milliseconds, usually seconds, but frequently tens of seconds or even hundreds of seconds.
typical code,
elapselp = default_timer() # timing start
port = 12571 # port number, many different ones used
while bound == 0:
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('', port))
bound = 1
elapselp1 = default_timer() - elapselp
print ('bind time = ', elapselp1)
As stated above elapselp1 can be at the low millisecond level, or 200 seconds which causes significant problems.
I usually find I can get back to short times by changing the port number used, which means changing on all the clients, but after some time running happily the times will increase again. Rebooting or powering down does not help. I am using Raspberry 4s and Zero Ws, no difference.
I suspect that some register is not clearing, but outside that am clueless. Can somebody advise please.
I am running Rasparian 3.6 and Python3
Thank you for all your replies, here is the remainder of this section of the code.
As I’m not sure how to input his I’m breaking it down over a number of comments.
elapselp = default_timer()
port =12571
while bound == 0:
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('', port))
bound = 1
elapselp1 = default_timer()- elapselp
print (‘bind time = ‘, elapselp2)
except:
dummy = 1
s1.listen(5)
print ('waiting for input ', end='')
while True:
conn, addr = s1.accept()
print ('connected by ', addr)
conn.send('thank you'.encode())
data = conn.recv(1024).decode()
print ('data = ', data)
time.sleep(5)
conn.close()
s1.close()
if data == '10':
startdaw = default_timer()
GPIO.output(22, GPIO.LOW)
print ('switch dining area heating off')
h1 = 0
dawl = edaw
startdawr = default_timer()
elif data == '11':
GPIO.output(22, GPIO.HIGH)
## A lot of other actions depending on data received here
else:
print ('another code ', data)
if not data:
break
print ('yet another')
I have a number of Raspberry pi Zeros running the code for test along with 7 doing so as part of my control system. The performance is very erratic.
One unit running through the code every 30 seconds in response to a client has been running over 5 days, majority of the bind times have been under 1 millsec, I see some between 1 and 10, but it has recorded one time of 130 seconds.
Another unit which failed to bind for over two hours has now completed over 33,000 binds (this one just closes after the bind, no if statements), and the longest time for a bind is 710 msec.
If I take out the try/except I get no error message, it just drops through and loops back.
I hope there is some useful information in there.

Array and matplotlib in Python

Python newbie here.
Currently I'm making a heartbeat signal detector with an Arduino for my school project.
I want to draw a plotter graph with a signal value that I sent from Arduino to Python, but I'm still not sure exact way to make a correct array and plot it in Python.
My arduino is connected with bluetooth module, and it is continuously send double integer value around 30~40 times/second.
In Python,I want to write a script that will receive 20 seconds of data, store it in a file, and plot it.
I built my code based on my basic C knowledge.
import serial, sys
from time import sleep
import time
import matplotlib.pyplot as plt
def read_BLE( ser ):
msg = ""
if( ser.in_waiting > 0 ):
msg = ser.readline( ser.in_waiting ).decode('utf-8')
return msg
with serial.Serial(port='COM7', baudrate=9600, timeout=1) as ser:
while(True) :
max_time = int(input('20')) #limit time : 20seconds
start_time = time.time() # remember when we started
while (time.time() - start_time) < max_time:
values = []
currenttime = []
i,j=0
currenttime[i] = (time.time() - start_time)
values[j] = read_BLE( ser )
i += 1
j += 1
plt.plot(currenttime, values)
Restructured part of your code, fixed a couple of breaking bugs, now it should work assuming your other parts of code is correct:
with serial.Serial(port='COM7', baudrate=9600, timeout=1) as ser:
values = [] # Initiate your list before the loop!
currenttime = []
max_time = 20 #limit time : 20seconds
start_time = time.time() # remember when we started
while True:
if (time.time() - start_time) > max_time:
break # if time elapsed larger than max_time, break out of loop
currenttime.append(time.time() - start_time)
values.append(read_BLE(ser)) # python list has no set length. just append to it.
plt.plot(currenttime, values)
Python list has no fixed memory allocation, .append will always add a element without causing memory issue -> It's just reference passing really. You also want to initiate your list before loop other wise each loop will overwrite and have a new list

python - issues with time.clock()/time()

I wrote a system to exchange crc-checked struct data between an arduino nano and my python script. This is working pretty well but when i let the system run i get unexpected output on my python monitor (using pycharm)
print "Took ", (time.time() - timeout), " s" sometimes prints out Took 0.0 s.
Usually it prints Took 0.0160000324249 s.
Using win7-64bit professional.
From time doc : Return the time in seconds since the epoch as a floating point number. Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second.
I´m looking for something like millis() thats enough precision for my case
Code Python :
import serial
import time
import binascii
import struct
from ctypes import *
arduino = serial.Serial()
def receive_struct2():
start = 0x85
detected_start = False
arduino.baudrate = 57600
arduino.timeout = 0
arduino.port = 'COM8'
try:
arduino.open()
except serial.SerialException, e:
print e
while True:
if(arduino.inWaiting() >= 1 and detected_start == False):
data = ord(arduino.read())
if data == start:
print "Detected begin"
detected_start = True
else: print chr(data),
if arduino.inWaiting() >= 1 and detected_start == True:
message_length = ord(arduino.read())
#print "Got message length ", message_length
timeout = time.time()
while time.time() - timeout <= 0.3 and arduino.inWaiting() < message_length-1:pass
print "Took ", (time.time() - timeout), " s"
....
Summary: Use timeit.default_timer() instead of time.time(), to measure a short duration.
16ms error for time.time() is not surprising on Windows.
Currently, Python uses GetSystemTimeAsFileTime() to implement time.time() on Windows that has the resolution (precision) of 0.1ms (instead of ftime()'s 1ms) and the accuracy is between 0.5 ms and 15 ms (you could change it system-wide using NtSetTimerResolution()). See Python bug: Use GetSystemTimeAsFileTime() to get a resolution of 100 ns on Windows and another SO question: How does python's time.time() method work?
A better alternative to measure short time intervals on Windows is to use time.clock() that is implemented using QueryPerformanceCounter() on Windows. For portability, you could use timeit.default_timer that is assigned to time.clock() on Windows, time.time() on other systems, and it is time.perf_counter() since Python3.3. See Python - time.clock() vs. time.time() - accuracy?

why does a print() affect how com1 is read?

I'm writing an interface for an old piece of electronic equipment that uses RS232 serial. I've run into a problem that I can't seem to solve. Here is the original code
def readMyPort():
global readPort
while True: #always loop
if readPort: # only do something of the port is active
dataString = b''
while (mySerialPort.inWaiting()>0):
data = mySerialPort.read(1)
if (data == b'') or (data == b'\r') or (data == b'\n'):
if (dataString != b''):
myOutput.insert('1.0', (dataString + b'\n').decode())
dataString = b''
else:
dataString += data
The problem I face is that the instrument sends a string of 12 characters in response to a command, and I only seem to catch the last 4, and no, there are no '', '\r', or '\n' in the string. In an effort to troubleshoot I added a print(), as shown below. Magically I started to get all the data.
def readMyPort():
global readPort
while True: #always loop
if readPort: # only do something of the port is active
dataString = b''
while (mySerialPort.inWaiting()>0):
data = mySerialPort.read(1)
print(data) #<-------- the added line
if (data == b'') or (data == b'\r') or (data == b'\n'):
if (dataString != b''):
myOutput.insert('1.0', (dataString + b'\n').decode())
dataString = b''
else:
dataString += data
Now I don't want to have all that printing going on normally. I tried just adding a print('') and that works as well, but I still have all those \n getting printed. I tried print('', end = '\r') but that didn't work. Does anyone have an idea why? I don't think it is a speed issue. I'm only running 9600 baud. FYI: python 3.2 on a Win32 machine. This routine is launched in it's own thread.
The operation print(data) requires some time (relatively large) to print something to the console. So by adding the line print(data) you just add some delay inside your loop. You may verify this theory by substituting print(data) for time.sleep(0.1 or whatever small value) and checking that the problem is hopefully gone.
I think that the delay helps because without it mySerialPort.inWaiting() may becomes 0 sometimes (receive buffer is empty) before the transaction is actually completed. Your instrument can't simply output data that fast. In your final version of the code you may add time.sleep() instead of print(data).
Following the answer of Konstantin, it appears that the serial port needs some time to adjust the buffer and counters, so adding a small delay in the loop solved my problem. 1 ms is not enough but 10 ms is. The final code is:
def readMyPort():
global readPort
while True: #always loop
if readPort: # only do something if the port is active
dataString = b''
while (mySerialPort.inWaiting()>0): #if something is in the buffer
data = mySerialPort.read(1)
if (data == b'') or (data == b'\r') or (data == b'\n'):
if (dataString != b''): #don't output empty strings
myOutput.insert('1.0', (dataString + b'\n').decode())
dataString = b''
else:
dataString += data
time.sleep(0.01) #slow the loop down a bit
I do continue to wonder if there is a more elegant solution.

How to quickly read single byte serial data using Python

I am reading serial data in Python using the following code:
port = "COM11"
baud = 460800
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
while 1:
# Read from serial port, blocking
data =ser.read(1)
print data
# some further processing of data
I am sending data at very fast rate but when I use this code I am getting data at a very slow rate, maybe around 2 - 3 data per second. This is too slow because I want to do real time plotting.
So, instead of above code I tried:
while 1:
# Read from serial port, blocking
data =ser.read(1)
data1=(data)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data1 = (data1 + ser.read(n))
print data1
Now the speed at which data is updated is the same but instead of a single byte I am checking a number of bytes in input queue and reading them. I am receiving around 3850 bytes per loop so this one appears much faster to me but in fact it is almost the same, the only change is that I am not reading a greater number of bytes.
I want to read a single byte and check for the real time it was received. To do so I cannot use second method where I use ser.inWaiting(). How can I read single byte data faster than using the approaches above?
Here's some test code I wrote for a project that you can try different baud settings with. Basically it sends out some data on Tx (which could be connected directly to Rx) and expects the data to be echoed back. It then compares the returned data with the sent data and lets you know if/when errors occur. Note that if there are no errors then the output will remain blank and at the end of test it will print "0 Comm Errors".
import serial, time
test_data = "hello this is so freakin cool!!!" + '\r' #Must always be terminated with '\r'
echo_timeout = 1 #the time allotted to read back the test_data string in seconds
cycleNum = 0
errors = 0
try:
ser = serial.Serial(port="COM1", baudrate=115200, timeout=1)
ser.flush()
print "starting test"
for x in xrange(100):
cycleNum += 1
d = ser.write(test_data)
ret_char = returned = ''
start_time = time.time()
while (ret_char <> '\r') and (time.time() - start_time < echo_timeout):
ret_char = ser.read(1)
returned += ret_char
if not returned == test_data:
errors += 1
print "Cycle: %d Sent: %s Received: %s" % (cycleNum, repr(test_data), repr(returned) )
except Exception as e:
print 'Python Error:', e
finally:
if 'ser' in locals():
print "%d Comm Errors" % errors
if ser.isOpen():
ser.close()
print "Port Was Successfully Closed"
else:
print "Port Already Closed"
else:
print "Serial Variable Was Never Initialized"

Categories