I was trying convert sequential code of port scanner to become fast as it's so slow :(.
Sequential code
import sys ,socket
from datetime import datetime
from threading import Thread
def target():
t=input(str("Enter target:"))
target=socket.gethostbyname(t)
try:
for p in range(1,1026):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
result=s.connect_ex((target,p))
if result==0:
service=socket.getservbyport(p)
print(f"port {p} is open service {service}")
else:
print(f"port {p} is close")
s.close()
except KeyboardInterrupt:
sys.exit()
except socket.error:
print("Host not responding")
def main():
target()
if __name__=="__main__":
main()
I successfully convert it Faster But I want to get successful output only in ThreadPoolexecutor
but I can't here What I do.
Fast Code
import socket
import threading
import concurrent.futures
import re
def scan(ip, port):
lock = threading.Lock()
scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scanner.settimeout(.1)
ip = re.sub("(https:// | http:// | \/)", '', ip)
ip = socket.gethostbyname(ip)
try:
scanner.connect((ip, port))
scanner.close()
with lock:
result = f"Port {port} is OPEN Running {socket.getservbyport(port)}"
print(result)
return result
except:
pass
def run(ip_num: str, scan_fn, nums_ports: int) -> list:
result = []
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
for port in range(nums_ports):
future = executor.submit(scan_fn, ip_num, port 1)
result.append(future.result())
print(result) # empty
return result
def main():
ip = input("target> ")
run(ip, scan, 1025)
# with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
# for port in range(1025):
# executor.submit(scan, ip, port 1)
if __name__ == "__main__":
main()
output if Target google.com
target> google.com
Port 80 is OPEN Running http
Port 443 is OPEN Running https
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'Port 80 is OPEN Running http', None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'Port 443 is OPEN Running https', None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
this above Output comes out after a long time how to make it faster and just take the successful result of that printed in first.
CodePudding user response:
The reason your program is slow is here:
def run(ip_num: str, scan_fn, nums_ports: int) -> list:
result = []
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
for port in range(nums_ports):
future = executor.submit(scan_fn, ip_num, port 1)
result.append(future.result()) # Waits for function to return a value
print(result)
return result
The call to future.result()
doesn't return until the future is done. Your main thread must wait until one of your secondary threads runs the function scan_fn
(which is actually the function named scan
). The future isn't done until scan
runs, finishes and returns a value. Even though you are running in a Pool, the logic of your program forces the calls to scan
to execute one at a time. You get no benefit at all from multithreading.
There are a couple of ways to fix this. You might consider using the capability of pool.map but here is a simple approach that is similar to your existing program, using pool.submit
. I made no changes to the function scan
. I hard-coded the url because I got tired typing "google.com" at the prompt :-)
import socket
import threading
import concurrent.futures
import re
import time
def scan(ip, port):
lock = threading.Lock()
scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scanner.settimeout(.1)
ip = re.sub("(https:// | http:// | \/)", '', ip)
ip = socket.gethostbyname(ip)
try:
scanner.connect((ip, port))
scanner.close()
with lock:
result = f"Port {port} is OPEN Running {socket.getservbyport(port)}"
print(result)
return result
except:
pass
def run(ip_num: str, scan_fn, nums_ports: int) -> list:
futures = []
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
for port in range(nums_ports):
futures.append(executor.submit(scan_fn, ip_num, port 1))
# At this point all the futures are pending, and are running
# in 100 other threads
result = []
for future in futures:
r = future.result() # Wait on each result
if r is not None: # Save only the non-None results
result.append(r)
print(result)
return result
def main():
t = time.time()
run("google.com", scan, 1025)
print("Total execution time", time.time() - t)
if __name__ == "__main__":
main()
The program output is:
Port 80 is OPEN Running http
Port 443 is OPEN Running https
['Port 80 is OPEN Running http', 'Port 443 is OPEN Running https']
Total execution time 1.2854032516479492
The execution time for 1025 scans is only 1.28 seconds.