I wrote the following small script in python which scans for open tcp ports but it runs slow, I want to improve performance by using threads, how can I implement such feature?
socket.setdefaulttimeout(0.01)
for port in range(0, 65536):
s = None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if s.connect_ex((sys.argv[1], port)) == 0:
open_ports.append(port)
s.close()
I would like to set the number of threads via a variable.
CodePudding user response:
Since the python is one of the "slowest" languages and the operation that you'd like to perform is simple, i'd suggest you to use c lang or any other mid-low level languages.
Multithreading to increase speed in a naturally slow language is just a futile effort, my opinion.
There're tons of examples online I'd suggest you to check https://codereview.stackexchange.com/questions/85553/simple-c-port-scanner
CodePudding user response:
I'd write something like:
import socket
from multiprocessing.pool import ThreadPool
def check_socket(host, port):
socket.setdefaulttimeout(0.01)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# return port if open, None otherwise
return port if s.connect_ex((host, port)) == 0 else None
def main(host):
with ThreadPool() as pool:
result = pool.starmap(check_socket, ((host, port) for port in range(0, 65536)))
# Pull out the list of open ports
return [x for x in result if x is not None]
CodePudding user response:
Put your code in a function start_scan(port_range)
And Check the asyncio library:
asyncio.create_task(start_scan(port_range))
Then you can have a loop for the number of threads you want, and you create as much task as you want. Then you await them one per one, or gather them.
See https://docs.python.org/3/library/asyncio-task.html
======= EDIT =======
To answer the question, how to split the range in sub list:
import math
def split_ports(ports, threads):
ports_per_threads = [[]]
n_port_per_thread = math.ceil(len(ports)/threads)
i = 0
t = 0
for p in ports:
i =1
if (i > n_port_per_thread):
i = 0
t = 1
ports_per_threads.append(list())
ports_per_threads[t].append(p)
ports = range(100, 200)
ports_lists = split_ports(ports, 4)
That would give you this result :
ports = range(1, 9)
ports_lists = split_ports(ports, 4)
# -> [[1, 2], [3, 4], [5, 6], [7, 8]]
ports_lists = split_ports(ports, 2)
# -> [[1, 2, 3, 4], [5, 6, 7, 8]]
