Of course! Here is a comprehensive guide to creating a Python port scanner, starting with a simple version and progressing to a more advanced, practical one.

We'll cover:
- The Core Concept: How port scanning works.
- A Simple, Single-Threaded Scanner: The most basic approach.
- A Fast, Multi-Threaded Scanner: A much more efficient version.
- A Complete, Advanced Scanner: A robust script with features like service detection, output formatting, and command-line arguments.
The Core Concept: How Port Scanning Works
At its heart, port scanning is like knocking on doors (ports) of a building (a server) to see if anyone is home.
- IP Address: The address of the server (e.g.,
168.1.1orgoogle.com). - Port: A numbered door (1 to 65535). Common services use specific ports (e.g., Port 80 for HTTP, 22 for SSH).
- TCP Connection: The scanner attempts to establish a full TCP connection to a specific port on the target IP.
- If the connection is successful, the port is open.
- If the connection is refused, the port is closed.
- If there's no response after a while, the port is filtered (likely by a firewall).
Python's built-in socket library is perfect for this.
Simple, Single-Threaded Port Scanner
This version is easy to understand but very slow because it checks one port at a time.

The Code
import socket
def scan_port(ip, port):
"""
Attempts to connect to a single port on a given IP address.
Returns True if the port is open, False otherwise.
"""
try:
# Create a socket object
# AF_INET for IPv4, SOCK_STREAM for TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set a timeout of 1 second for the connection attempt
s.settimeout(1)
# Attempt to connect to the IP and port
result = s.connect_ex((ip, port))
if result == 0:
# connect_ex returns 0 on a successful connection
print(f"Port {port}: OPEN")
return True
else:
return False
s.close()
except socket.error:
return False
except Exception as e:
print(f"An error occurred with port {port}: {e}")
return False
if __name__ == "__main__":
target_ip = input("Enter the target IP address: ")
# Common ports to scan
common_ports = [21, 22, 23, 25, 53, 80, 110, 143, 443, 993, 995]
print(f"\nScanning {target_ip} for common ports...")
for port in common_ports:
scan_port(target_ip, port)
print("\nScan complete.")
How to Run It
- Save the code as
simple_scanner.py. - Run it from your terminal:
python simple_scanner.py - Enter an IP address when prompted.
Limitation: This scanner is sequential. It waits for the connection to port 21 to finish (or time out) before trying port 22. For a full port scan, this would take hours.
Fast, Multi-Threaded Port Scanner
To speed things up, we can use threads. A thread is a small unit of a process that can run concurrently. We can create a thread for each port we want to scan, allowing us to check many ports at the same time.
We'll use Python's concurrent.futures module, which makes working with threads incredibly easy.
The Code
import socket
import concurrent.futures
def scan_port(ip, port):
"""Attempts to connect to a single port. Returns the port if it's open."""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.5) # Shorter timeout for speed
result = s.connect_ex((ip, port))
if result == 0:
return port
except:
pass
return None
def scan_target(ip, port_list):
"""Scans a list of ports on a target IP using a thread pool."""
print(f"Scanning {ip}...")
open_ports = []
# Use a ThreadPoolExecutor to manage threads
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
# Create a future for each port scan
future_to_port = {executor.submit(scan_port, ip, port): port for port in port_list}
# As each future completes, process the result
for future in concurrent.futures.as_completed(future_to_port):
port = future_to_port[future]
try:
result_port = future.result()
if result_port:
open_ports.append(result_port)
print(f"Port {result_port}: OPEN")
except Exception as e:
print(f"Error scanning port {port}: {e}")
return open_ports
if __name__ == "__main__":
target_ip = input("Enter the target IP address: ")
# Scan the top 1000 most common ports
# You can find a list online or use a library like 'socket'
common_ports = [
21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 443, 993, 995,
1723, 3306, 3389, 5432, 5900, 8080, 8443
] # This is a shortened list for demonstration
open_ports = scan_target(target_ip, common_ports)
print("\n--- Scan Summary ---")
if open_ports:
print(f"Found {len(open_ports)} open ports on {target_ip}:")
for port in sorted(open_ports):
print(f" - {port}")
else:
print(f"No open ports found on {target_ip} among the scanned ports.")
How to Run It
- Save as
threaded_scanner.py. - Run with
python threaded_scanner.py. - Enter an IP address.
Why it's faster: The ThreadPoolExecutor creates a pool of worker threads (100 in this case). It assigns a port scan task to any available thread, allowing hundreds of connection attempts to happen in parallel.
Complete, Advanced Port Scanner
This is a full-featured script that is much more practical. It includes:
- Command-line arguments (
-ifor IP,-pfor port range). - Service detection (looks up the service name for an open port).
- Clean, organized output.
- Error handling for invalid inputs.
The Code
import socket
import concurrent.futures
import argparse
import sys
# A dictionary of common ports and their services
PORT_SERVICES = {
21: "FTP", 22: "SSH", 23: "Telnet", 25: "SMTP", 53: "DNS",
80: "HTTP", 110: "POP3", 143: "IMAP", 443: "HTTPS", 993: "IMAPS",
995: "POP3S", 3306: "MySQL", 3389: "RDP", 5432: "PostgreSQL",
5900: "VNC", 8080: "HTTP-Alt", 8443: "HTTPS-Alt"
}
def scan_port(ip, port):
"""Scans a single port and returns a tuple of (port, service) if open."""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2) # Very short timeout for speed
result = s.connect_ex((ip, port))
if result == 0:
service = PORT_SERVICES.get(port, "Unknown")
return (port, service)
except (socket.timeout, socket.error):
pass
return None
def parse_port_range(port_range_str):
"""Parses a port range string like '1-1024' or '22,80,443' into a list of ports."""
ports = []
if ',' in port_range_str:
for part in port_range_str.split(','):
ports.extend(parse_port_range(part.strip()))
elif '-' in port_range_str:
start, end = map(int, port_range_str.split('-'))
ports.extend(range(start, end + 1))
else:
ports.append(int(port_range_str))
return sorted(list(set(ports))) # Remove duplicates and sort
def main():
parser = argparse.ArgumentParser(description="A fast and simple Python port scanner.")
parser.add_argument("-i", "--ip", required=True, help="Target IP address or hostname.")
parser.add_argument("-p", "--ports", default="1-1024", help="Port range to scan (e.g., '80', '1-1024', '22,80,443').")
args = parser.parse_args()
try:
# Resolve hostname to IP if necessary
target_ip = socket.gethostbyname(args.ip)
except socket.gaierror:
print(f"Error: Could not resolve hostname '{args.ip}'")
sys.exit(1)
try:
ports_to_scan = parse_port_range(args.ports)
except ValueError:
print("Error: Invalid port range format. Use '80', '1-1024', or '22,80,443'.")
sys.exit(1)
print(f"[*] Target: {target_ip} ({args.ip})")
print(f"[*] Scanning {len(ports_to_scan)} ports...")
open_ports = []
# Use a thread pool for efficiency
with concurrent.futures.ThreadPoolExecutor(max_workers=200) as executor:
future_to_port = {executor.submit(scan_port, target_ip, port): port for port in ports_to_scan}
for future in concurrent.futures.as_completed(future_to_port):
result = future.result()
if result:
port, service = result
open_ports.append((port, service))
print(f" [+] {port}/tcp {service}")
print("\n--- Scan Complete ---")
if open_ports:
print(f"Found {len(open_ports)} open ports on {target_ip}:")
for port, service in sorted(open_ports):
print(f" - {port}/tcp {service}")
else:
print("No open ports found.")
if __name__ == "__main__":
main()
How to Run It
Save this as advanced_scanner.py. You can now run it from the command line with various options.
Basic Usage (scan common ports on a local machine):
python advanced_scanner.py -i 127.0.0.1
Scan a specific port:
python advanced_scanner.py -i scanme.nmap.org -p 80
Scan a range of ports:
python advanced_scanner.py -i scanme.nmap.org -p 1-1000
Scan multiple specific ports:
python advanced_scanner.py -i scanme.nmap.org -p 22,80,443,3389
⚠️ Important Legal and Ethical Warning
Port scanning can be detected by Intrusion Detection Systems (IDS) and firewalls. Scanning a machine that you do not own or have explicit, written permission to scan is illegal in many jurisdictions and can be considered a precursor to an attack.
- Only scan systems you own or have explicit permission to test.
- Be responsible. Aggressive scanning can disrupt network services.
- This tool is for educational purposes and learning about network security. Use it wisely and ethically.
