# Python Port Scanner

This utility scans a target IP address or hostname for open ports. It uses the `socket` module to attempt connections and `threading` to scan multiple ports simultaneously for performance.

**Modules Used:**
*   [[programming/python/modules/socket-module|socket]]: To create network connections and check ports.
*   `threading`: To run multiple scan attempts concurrently.
*   `queue`: To manage the list of ports to be scanned in a thread-safe way.
*   [[programming/python/modules/argparse-module|argparse]]: To handle command-line arguments.

## The Code

Save this as `port_scanner.py`.

```python
import socket
import threading
import queue
import argparse
from datetime import datetime

# Thread-safe print lock to prevent garbled output
print_lock = threading.Lock()

def scan_port(target, port):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(1) # Timeout for connection attempt
        
        # connect_ex returns 0 if connection is successful, error code otherwise
        result = s.connect_ex((target, port))
        if result == 0:
            with print_lock:
                print(f"Port {port}: OPEN")
        s.close()
    except Exception:
        pass

def worker(target, q):
    while True:
        port = q.get()
        scan_port(target, port)
        q.task_done()

def main(target, start_port, end_port, thread_count):
    print(f"Scanning target: {target}")
    print(f"Scanning ports: {start_port}-{end_port}")
    print(f"Time started: {datetime.now()}")
    print("-" * 50)

    q = queue.Queue()

    # Create threads
    for _ in range(thread_count):
        t = threading.Thread(target=worker, args=(target, q))
        t.daemon = True # Daemon threads exit when main program exits
        t.start()

    # Fill queue with ports
    for port in range(start_port, end_port + 1):
        q.put(port)

    # Wait for queue to be empty
    q.join()
    print("-" * 50)
    print("Scanning completed")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Multi-threaded Port Scanner")
    parser.add_argument("target", help="Target IP or Hostname")
    parser.add_argument("--start", type=int, default=1, help="Start Port (default: 1)")
    parser.add_argument("--end", type=int, default=1024, help="End Port (default: 1024)")
    parser.add_argument("--threads", type=int, default=100, help="Number of threads (default: 100)")
    
    args = parser.parse_args()
    
    # Resolve hostname to IP
    try:
        target_ip = socket.gethostbyname(args.target)
    except socket.gaierror:
        print("Hostname could not be resolved.")
        exit()

    main(target_ip, args.start, args.end, args.threads)
```

## Usage

```bash
# Scan common ports (1-1024) on localhost
python port_scanner.py localhost

# Scan a specific range on a server
python port_scanner.py 192.168.1.1 --start 80 --end 8080 --threads 200
```

[[programming/python/python]]