Python3实现TCP端口扫描器:从基础到多线程优化
本文详细介绍如何使用Python3编写TCP端口扫描器。从基础的TCP全连接扫描原理出发,逐步引入多线程技术解决效率瓶颈,并结合argparse模块实现命令行参数解析。内容涵盖SYN、FIN等多种扫描类型对比,提供完整代码示例,适合网络安全初学者快速掌握端口扫描的核心实现思路。
在渗透测试的初始阶段,信息搜集是必不可少的一环,而端口扫描则是其中至关重要的一步。通过执行端口扫描,我们可以掌握目标主机开放了哪些服务,甚至能依据这些服务推测潜在的安全漏洞。常见的TCP端口扫描类型主要包括以下几种:
TCP connect扫描(全连接扫描):该方法直接尝试与目标端口建立连接,完整执行TCP三次握手过程。其优点是扫描结果较为准确,但缺点是速度较慢,且容易被目标系统的安全机制检测到。
TCP SYN扫描(半开放扫描):此方法仅发送一个SYN数据包以启动TCP会话,并等待目标响应。若收到RST包,说明端口关闭;若收到SYN/ACK包,则表明端口处于开放状态。
TCP FIN扫描:该方法发送一个标记为拆除活动TCP连接的FIN包。如果目标返回RST包,则表明相应端口处于关闭状态。
TCP XMAS扫描:通过发送设置了PSH、FIN和URG标志位的数据包(即TCP标志位均为1)进行探测。若收到RST包,则说明端口关闭。
接下来,我们将使用Python3来实现一个基于TCP全连接的端口扫描器,正式进入代码实现环节。
编码实战
全连接扫描的核心逻辑是针对不同端口发起TCP连接,并根据连接是否成功来判断端口状态。现在,我们先来实现一个最基础的端口扫描器:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
def portScanner(host,port):
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
print('[+] %d open' % port)
s.close()
except:
print('[-] %d close' % port)
def main():
setdefaulttimeout(1)
for p in range(1,1024):
portScanner('192.168.0.100',p)
if __name__ == '__main__':
main()
这段代码的核心在于portScanner函数。从代码逻辑可以看出,它仅执行了简单的TCP连接操作:若连接成功,则判定端口开放;否则视为关闭。以下是运行结果的展示:

这种扫描方式的效率显然过低,实际运行速度也很慢,主要原因在于我们设置了1秒的默认超时时间。如果扫描10000个端口,等待时间将极其漫长。最简单的优化方案是利用多线程来提升效率。尽管Python的多线程机制存在一定局限,但它至少允许我们在等待I/O时执行其他任务。此外,由于之前扫描的端口数量较多,输出信息杂乱不便阅读,本次我们将仅显示我们关心的打开的端口,并在扫描结束时统计并显示打开端口的总数。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
import threading
lock = threading.Lock()
openNum = 0
threads = []
def portScanner(host,port):
global openNum
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
lock.acquire()
openNum+=1
print('[+] %d open' % port)
lock.release()
s.close()
except:
pass
def main():
setdefaulttimeout(1)
for p in range(1,1024):
t = threading.Thread(target=portScanner,args=('192.168.0.100',p))
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The scan is complete!')
print('[*] A total of %d open port ' % (openNum))
if __name__ == '__main__':
main()
查看运行效果,如下图所示:

现在的输出结果是否清晰了许多?至此,我们解决了效率问题。接下来,还需要为扫描器添加参数解析功能,使其更加实用,避免每次修改扫描目标或端口时都需改动代码。
我们将使用Python3自带的标准模块argparse来进行参数解析,从而省去手动解析字符串的繁琐工作。代码如下:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
import threading
import argparse
lock = threading.Lock()
openNum = 0
threads = []
def portScanner(host,port):
global openNum
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
lock.acquire()
openNum+=1
print('[+] %d open' % port)
lock.release()
s.close()
except:
pass
def main():
p = argparse.ArgumentParser(description='Port scanner!.')
p.add_argument('-H', dest='hosts', type=str)
args = p.parse_args()
hostList = args.hosts.split(',')
setdefaulttimeout(1)
for host in hostList:
print('Scanning the host:%s......' % (host))
for p in range(1,1024):
t = threading.Thread(target=portScanner,args=(host,p))
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The host:%s scan is complete!' % (host))
print('[*] A total of %d open port ' % (openNum))
if __name__ == '__main__':
main()
查看运行效果,如下图所示:

至此,我们的端口扫描器已基本完成。虽然功能相对简单,但旨在阐述端口扫描器的基本实现思路。更详细的功能可以基于此基础结构逐步完善。
小结
本节主要讲解了使用Python3实现简单端口扫描器的过程。本次实验采用了TCP全连接方式,通过不断尝试连接主机端口来判断其开放状态。尽管该方法存在一定局限性,但最适合初学者学习。对于希望举一反三的读者,可以根据协议与端口的对应关系,在扫描时同时输出协议信息,以提升可读性。更复杂的功能大家可以作为练习自行探索。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













