I am trying to write a simple tool that measures the TCP port open, the code works well.
The issue I have is that when I compare the TCP ping result to other tools, such psping (Sysinternals), tcpping , check_tcp(Nagios), I get much lower results than my code.
In my code open TCP port open takes around 9~10ms, others tools takes 0.200~0.500ms
in the beginning, thought its related to the case if I have multiple interfaces on my computer, I added to bind to the correct interface and didn't change the results.
In addition, i found that the difference between python and other tools, I used Wireshark to capture both python and psping, and I found that
the final handshake from client side FIN, ACK is much slower in Python than psping and that is the difference the 10ms.
Is there any flag in Python TCP to make it faster?
My question is, why I get such different results?
Please advice
Thanks
as suggested post from babygame0ver solve the "latency" issue added threading and latency now much other tools
Thanks
#!/usr/bin/env python3
"""
TCP Ping Test (defaults to port 80, 10000 packets)
Usage: ./tcpping.py host [port] [maxCount]
- Ctrl-C Exits with Results
"""
import sys
import socket
import time
import signal
from timeit import default_timer as timer
import threading
host = None
port = 80
a = time.clock()
time.sleep(2)
b = time.clock()
print(b-a)
# Default to 10000 connections max
maxCount = 10000
count = 0
## Inputs
# Required Host
try:
host = sys.argv[1]
except IndexError:
print("Usage: tcpping.py host [port] [maxCount]")
sys.exit(1)
# Optional Port
try:
port = int(sys.argv[2])
except ValueError:
print("Error: Port Must be Integer:", sys.argv[3])
sys.exit(1)
except IndexError:
pass
# Optional maxCount
try:
maxCount = int(sys.argv[3])
except ValueError:
print("Error: Max Count Value Must be Integer", sys.argv[3])
sys.exit(1)
except IndexError:
pass
# 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)
s.bind(('192.168.10.19', 0))
# 1sec Timeout
s.settimeout(1)
# Try to Connect
try:
# Start a timer
t = threading.Thread(target=s.connect((host, int(port))))
#threads.append(t)
s_start = timer()
t.start()
# Stop Timer
s_stop = timer()
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()
Related
Good morning, I am using git hub examples as a base to make a can bus connection through the pican2 duo can, the python can configuration and the pican2 drivers were installed correctly the problem comes when running the code since A few seconds after running the program I get the extended_id and socketcan_native error, it appears as follows:
" init() got an unexpected keyword argument 'is_extended_id'".
I am viewing the comments and it has worked for several of them and several have the same problem. If anyone has the same problem or has already solved it, can you guide me.
I am using python can 4.1.0.
And tried to fix it by downloading older versions of python can, but when entering the commands : sudo apt-get update
sudo apt-get upgrade automatically upgrades me to the newest version of python. I have to send these commands to be able to use the pican2 duo can card.
I leave the url that I am using
https://github.com/skpang/PiCAN-Python-examples/blob/master/obdii_logger.py
#!/usr/bin/python3
#
## obdii_logger.py
#
# This python3 program sends out OBDII request then logs the reply to the sd card.
# For use with PiCAN boards on the Raspberry Pi
# http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html
#
# Make sure Python-CAN is installed first http://skpang.co.uk/blog/archives/1220
#
# 24-08-16 SK Pang
#
import RPi.GPIO as GPIO
import can
import time
import os
import queue
from threading import Thread
led = 22
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led,GPIO.OUT)
GPIO.output(led,True)
# For a list of PIDs visit https://en.wikipedia.org/wiki/OBD-II_PIDs
ENGINE_COOLANT_TEMP = 0x05
ENGINE_RPM = 0x0C
VEHICLE_SPEED = 0x0D
MAF_SENSOR = 0x10
O2_VOLTAGE = 0x14
THROTTLE = 0x11
PID_REQUEST = 0x7DF
PID_REPLY = 0x7E8
outfile = open('log.txt','w')
print('\n\rCAN Rx test')
print('Bring up CAN0....')
# Bring up can0 interface at 500kbps
os.system("sudo /sbin/ip link set can0 up type can bitrate 500000")
time.sleep(0.1)
print('Ready')
try:
bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except OSError:
print('Cannot find PiCAN board.')
GPIO.output(led,False)
exit()
def can_rx_task(): # Receive thread
while True:
message = bus.recv()
if message.arbitration_id == PID_REPLY:
q.put(message) # Put message into queue
def can_tx_task(): # Transmit thread
while True:
GPIO.output(led,True)
# Sent a Engine coolant temperature request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_COOLANT_TEMP,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Engine RPM request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_RPM,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Vehicle speed request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,VEHICLE_SPEED,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Throttle position request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,THROTTLE,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
GPIO.output(led,False)
time.sleep(0.1)
q = queue.Queue()
rx = Thread(target = can_rx_task)
rx.start()
tx = Thread(target = can_tx_task)
tx.start()
temperature = 0
rpm = 0
speed = 0
throttle = 0
c = ''
count = 0
# Main loop
try:
while True:
for i in range(4):
while(q.empty() == True): # Wait until there is a message
pass
message = q.get()
c = '{0:f},{1:d},'.format(message.timestamp,count)
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_COOLANT_TEMP:
temperature = message.data[3] - 40 #Convert data into temperature in degree C
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_RPM:
rpm = round(((message.data[3]*256) + message.data[4])/4) # Convert data to RPM
if message.arbitration_id == PID_REPLY and message.data[2] == VEHICLE_SPEED:
speed = message.data[3] # Convert data to km
if message.arbitration_id == PID_REPLY and message.data[2] == THROTTLE:
throttle = round((message.data[3]*100)/255) # Conver data to %
c += '{0:d},{1:d},{2:d},{3:d}'.format(temperature,rpm,speed,throttle)
print('\r {} '.format(c))
print(c,file = outfile) # Save data to file
count += 1
except KeyboardInterrupt:
#Catch keyboard interrupt
GPIO.output(led,False)
outfile.close() # Close logger file
os.system("sudo /sbin/ip link set can0 down")
print('\n\rKeyboard interrtupt')
I found through experimentation that changing 'socketcan-native' to 'socketcan' got me past that error. This worked for me:
bus = can.interface.Bus(channel = 'can0', bustype = 'socketcan')
The can.interface.Bus() call works for me when I use:
message = can.Message(arbitration_id=0x111, data=[0, 1, 2, 3, 4, 5, 6, 7], is_extended_id=False)
When I got the sample code it didn't have:
is_exteneded_id
Instead it had:
extended_id
I notice in your code you have:
extended_id
I want to have a Raspberry Pi collect data simultaneously from multiple Mbed microcontrollers with TCP sockets. Right now I have 2 microcontrollers sending out different data packets at regular intervals. The microcontrollers get an error message any time the package is not received so after 3 consecutive failed sends it will close and reopen its socket. With my current code I have 100% packet transfer success with only 1 microcontroller powered but with a second one sending packets it may work briefly but then will begin seeing missed packets and occasional errors.
#The server code is
import sys
import socket
from threading import Thread
from socketserver import ThreadingMixIn
# Multithreaded Python server : TCP Server Socket Thread Pool
class ClientThread(Thread):
def __init__(self,ip,port):
Thread.__init__(self)
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + ip + ":" + str(port))
def run(self):
while True :
data = conn.recv(64)
#print ("Server received from " + ip + ".")
if self.ip == '192.168.1.45':
print("hello GPS")
elif self.ip == '192.168.1.253':
time = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3])
vibes = [0]*10
for i in range(0, 10):
vibes[i] = data[(i*2)+4] << 8 | data [(i*2)+5]
print ("Server received from " + ip + " data: ", time, vibes[0], vibes[1], vibes[2], vibes[3], vibes[4], vibes[5], vibes[6], vibes[7], vibes[8], vibes[9])
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0'
TCP_PORT = 80
BUFFER_SIZE = 64 # Usually 1024, but we need quick response
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServer.bind((TCP_IP, TCP_PORT))
threads = []
while True:
tcpServer.listen(4)
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = tcpServer.accept()
newthread = ClientThread(ip,port)
newthread.start()
threads.append(newthread)
I don't really understand what is happening in this code but I assumed that the way it worked is whenever a new connection was made, a new while loop began and could operate at the same time as others. The terminal mostly prints one of the two messages randomly and on the microcontroller side when its sensor data isn't printed I can see the message not received error. Occasionally I see that a new thread is starting and sometimes an out of range error when sorting the packet.
> Server received from 192.168.1.253 data: 236604 12 6 6 25 12 12 37 18
> 18 48 Server received from 192.168.1.253 data: 236423 9 4 4 17 9 9 25
> 14 14 32 [+] New server socket thread started for 192.168.1.45:58418
> Multithreaded Python server : Waiting for connections from TCP
> clients... Server received from 192.168.1.45 data: 236423 8 6 6 16 12
> 12 23 18 18 30 hello GPS Exception in thread Thread-3: Traceback (most
> recent call last): File "/usr/lib/python3.9/threading.py", line 954,
> in _bootstrap_inner
> self.run() File "/home/pi/Documents/tcp_server2.py", line 25, in run
> vibes[i] = data[(i*2)+4] << 8 | data [(i*2)+5] IndexError: index out of range hello GPS hello GPS [+] New server socket thread started
> for 192.168.1.253:45001 Multithreaded Python server : Waiting for
> connections from TCP clients...
Can I receive multiple messages at the same time this way or do I need to do something like synchronizing the clients to not send at the same time? Is it better to put each client on a separate port and just set up tcpServer1, tcpServer2, tcpServer3,...?
Analysis:
IndexError: index out of range
This arises because your array doesn't have adequate bytes inside, that is, len(data)<=(i*2)+4 OR len(data)<=(i*2)+5.
Explanation:
After conn.recv(64), there is no guarantee that your data will receive an integral 64-length bytes array. Your argument 64 can only put a constaint that your data will be receive 64 bytes at most at a time, since accoding to Python Docs:
socket.recv(bufsize[, flags])
Receive data from the socket. The return value is a bytes object
representing the data received. The maximum amount of data to be received
at once is specified by bufsize.
...
Therefore you need a way to make sure that your data array contains all the bytes your need later on. One alternative is to wrap with a while{...} loop, repeatedly receiving data from your conn until it receive all 64 bytes.
Solution:
You can refer to myreceivce routine suggested in Python official tutorial:
# ...
def myreceive(self):
chunks = []
bytes_recd = 0
while bytes_recd < MSGLEN: # in your case, MSGLEN might be 64
chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
# ...
# ...
#Armali and #MichaelLee thank you so much for the help. I am new to Python so I couldn't figure out what to do with the conn variable. I didn't know things in the "main" count as global since it isn't in C++. I am currently receiving 100% of packets from 2 microcontrollers at 10Hz with this.
import sys
import socket
from threading import Thread
from socketserver import ThreadingMixIn
import time
# Multithreaded Python server : TCP Server Socket Thread Pool
#single thread to search for new clients
class FindClients(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
while True:
tcpServer.listen(5)
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = tcpServer.accept()
newthread = ClientThread(conn,ip,port)
newthread.start()
threads.append(newthread)
#thread for connected client to stay in
class ClientThread(Thread):
def __init__(self,conn,ip,port):
Thread.__init__(self)
self.conn = conn
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + self.ip + ":" + str(port))
def run(self):
while True :
chunks = []
bytes_recd = 0
if self.ip == '192.168.1.253':
MSGLEN = 64
while bytes_recd < MSGLEN:
chunk = self.conn.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
time = (chunk[0] << 24) | (chunk[1] << 16) | (chunk[2] << 8) | (chunk[3])
vibes = [0]*10
for i in range(0, 10):
vibes[i] = chunk[(i*2)+4] << 8 | chunk[(i*2)+5]
print ("Server received from " + self.ip + " data: ", time, vibes[0], vibes[1], vibes[2], vibes[3], vibes[4], vibes[5], vibes[6], vibes[7], vibes[8], vibes[9])
if self.ip == '192.168.1.45':
MSGLEN = 18
while bytes_recd < MSGLEN:
chunk = self.conn.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
print(chunks)
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0'
TCP_PORT = 80
BUFFER_SIZE = 64 # Usually 1024, but we need quick response
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#tcpServer.setblocking(False)
tcpServer.bind((TCP_IP, TCP_PORT))
threads = []
newthread = FindClients()
newthread.start()
while True:
Every ClientThread uses the same global conn, which is reassigned each time a new connection is accepted, so all those threads try to read from the most recent connection. You rather have to pass conn to the thread and have it store and use its private connection just as you do with ip and port.
When you corrected this, you also should print self.ip rather than ip in run.
Below is the code I am trying to run, however, I am not sure about how to make it loop for each item in the list.
Looking for some advice
import socket
import time
sock = sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
testinput = input('''Please enter the number corrosponding to the test you would like to carry out
1. HTTP Test to Horizon
Choice: ''')
if testinput == '1':
print('You have choosen test 1')
print('Test port 80 to xsi.unlimitedhorizon.co.uk...')
for i in ['88.215.60.155', '88.215.60.156', '88.215.60.166', '88.215.60.168']:
port80result = sock.connect_ex((i, 80))
if port80result == 0:
print('Test Successful for ' + i)
Running this, I would like to have the socket test, test each IP address in the list.
However I just get the below, and then it ends:
Please enter the number corresponding to the test you would like to carry out 1. HTTP Test to Horizon
Choice: 1
You have chosen test 1
Test port 80 to xsi.unlimitedhorizon.co.uk...
Test Successful for 88.215.60.155
As you can tell, I am still on a steep learning curve
Appreciate anyone's help :)
Thanks for the replies. I have been able to solve this.
- Added a socket timeout
- Added else: in case the test fails
Updated code below:
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
testinput = input('''Please enter the number corrosponding to the test you would like to carry out
1. HTTP Test to Horizon
Choice: ''')
if testinput == '1':
print('You have choosen test 1')
print('Test port 80 to xsi.unlimitedhorizon.co.uk...')
for i in ['88.215.60.155', '88.215.60.156', '88.215.60.166', '88.215.60.168']:
port80result = sock.connect_ex((i, 80))
socket.timeout(1)
if port80result == 10061:
print('Test Successful for ' + i)
else:
print(port80result)
what I have is
import time
r = 0
while True:
print(r)
r += 1
time.sleep(3)
number = input()
num = int(number)
#????????????
if num == r:
print('yes')
else:
print('no')
And what I want to do is make it so after every number printed there's a 3 second window for the user to input the value of r, and if the user does nothing then have the program move on. How do I do that?
Here is a working code using signal and Python 3.6+ That should run under any Unix & Unix-like systems and will fail under Windows:
import time
import signal
def handler_exception(signum, frame):
# Raise an exception if timeout
raise TimeoutError
def input_with_timeout(timeout=5):
# Set the signal handler
signal.signal(signal.SIGALRM, handler_exception)
# Set the alarm based on timeout
signal.alarm(timeout)
try:
number = input(f"You can edit your number during {timeout}s time: ")
return int(number)
finally:
signal.alarm(0)
r = 1
while True:
number = input("Enter your number: ")
num = int(number)
try:
num = input_with_timeout()
# Catch the exception
# print a message and continue the rest of the program
except TimeoutError:
print('\n[Timeout!]')
if num == r:
print('yes')
else:
print('no')
Demo 1: Execution without timeout
Enter your number: 2
You can edit your number during 5s time: 1
yes
Enter your number:
Demo 2: Execution with timeout
Enter your number: 2
You can edit your number during 5s time:
[Timeout!]
no
Enter your number:
Im trying to simulate two machines working, and failing at random times. When they fail they call assistance. These two machines is part of bigger system of different machines, which needs to know when its neighbor has failed to do its job.
So far, I have made the simulate of the two machines, but I cant figure out how to send messages to their neighbors without each machine needing to know the whole system?
This is what I have so far:
import simpy
import random
random_seed=42
MTTF = 3500
break_mean = 1 / MTTF
sim_time = 4 * 7*24*60 # 4 weeks 24/7
num_machines = 2
rep_time = 30
tpp = 20 #20 minutes to make each part
neighbour = 3 #How many should it send to?
#Creating a class called messaging which is an object.
class messaging(object):
#DEfing the initilizing function, and initilize self, Environment, and capacity which is set to infinity, by a simpy core-function.
def __init__(self, env, capacity=simpy.core.Infinity):
self.env = env
self.capacity = capacity
self.pipes = []
#Making a function which work on everything that is a part of the message. With name Put.
def put(self, value):
if not self.pipes: #How to get this error?
raise runtime_error('There are no output pipes.')
#Create a variable, events, store to it pipe values
events = broken_machine()
return self.env.all_of(events)
def get_output_conn(self):
#Set the capacity of pipe variable to store infinity.
pipe = simpy.Store(self.env, capacity=self.capacity)
#to each pipes, add(or append) pipe
self.pipes.append(pipe)
return pipe
def mesg_generator(number, env, out_pipe):
msg = ('Failed')
def message_reciever(name, env, in_pipe):
while True:
msg = yield in_pipe.get()
print("%s received message: %s" % (number, msg[1]))
def time_per_part():
return tpp
def ttf():
return random.expovariate(break_mean)
class Machine(object):
def __init__(self, env, number, repair):
#self.arg = arg
self.env = env
self.number = number
self.parts_made = 0
self.times_broken = 0
self.broken = False
self.process = env.process(self.working(repair))
env.process(self.broken_machine())
def working(self, repair):
while True:
work = time_per_part()
while work:
try:
begin = self.env.now
yield self.env.timeout(work)
work = 0
except simpy.Interrupt:
self.broken = True
work -= self.env.now - begin
with repair.request(priority = 1) as req:
yield req
yield self.env.timeout(rep_time)
self.times_broken +=1
yield message_reciever()
#print('Machine down')
self.broken = False #Machine fixed again
self.parts_made +=1
def broken_machine(self):
while True:
yield self.env.timeout(ttf())
if not self.broken:
self.process.interrupt()
def other_jobs(env, repair):
while True:
work = tpp
while work:
with repair.request(priority=2) as req:
yield req
try:
begin = env.now
yield env.timeout(work)
work = 0
except simpy.Interrupt:
work -= env.now - begin
print("This simulates machines 3 and 4 doing the same tasks.")
random.seed(random_seed)
env = simpy.Environment()
pipe = simpy.Store(env)
bc_pipe = messaging(env)
repair = simpy.PreemptiveResource(env, capacity = 1)
machines = [Machine(env, 'Machine %d' % i, repair)
for i in range(num_machines)]
env.process(other_jobs(env, repair))
env.run(until=sim_time)
#Show how many times each machine failed:
for machine in machines:
print("%s broke down %d times" %(machine.number, machine.times_broken))