用python编写nmap扫描工具--采用协程的方式

简介: 协程是一种轻量级的线程,协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。

 上一章节,我们采用多线程的技术去进行服务器端口的扫描,遗留了一些问题待优化,今天,我们采用协程的方式去尝试一下是否解决这个问题。

   

   协程是一种轻量级的线程,协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。也就是说同一线程下的一段代码执行着执行着就可以中断,然后跳去执行另一段代码,当再次回来执行代码块的时候,接着从之前中断的地方开始执行。

   

协程的优点

1、执行效率高,尤其是在线程数较多的情况下,与多线程对比的优势更明显

2、不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好,因为执行效率比多线程高很多。

缺点

1、无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

2、进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序


接下来,让我们通过一段代码来看一下运行的效果:

import gevent
from gevent import monkey
import time
def fun1():
    for num in range(3):
        print('fun1方法正在运行')
        #time.sleep(1)
def fun2():
    for num in range(3):
        print('fun2方法正在运行')
        #time.sleep(1)
# 创建协程对象
t1 = gevent.spawn(fun1)
t2 = gevent.spawn(fun2)
monkey.patch_all()
gevent.joinall([t1, t2])

以上代码执行的时候,输出结果如下:

fun1方法正在运行
fun1方法正在运行
fun2方法正在运行
fun2方法正在运行
fun2方法正在运行

是不是跟预想的不一样呢,是的,因为程序执行没有阻塞/中断,所以打印结果没有交叉打印 ,把time.sleep(1)放开后,再执行:

import gevent
from gevent import monkey
import time
def fun1():
    for num in range(3):
        print('fun1方法正在运行')
        time.sleep(1)  # 协程遇到耗时操作后会自动切换其他协程运行
def fun2():
    for num in range(3):
        print('fun2方法正在运行')
        time.sleep(1)  # 协程遇到耗时操作后会自动切换其他协程运行
# 创建协程对象
t1 = gevent.spawn(fun1)
t2 = gevent.spawn(fun2)
monkey.patch_all()
gevent.joinall([t1, t2])

打印结果如下:

fun1方法正在运行
fun2方法正在运行
fun1方法正在运行
fun2方法正在运行
fun1方法正在运行
fun2方法正在运行

代码说明:

本次采用gevent库实现协程的相关操作,在使用之前需要先安装该插件。

安装命令:pip install gevent

gevent.spawn()函数:创建协程对象

gevnet.joinall([传入携程对象列表]):会等待所有协程对象运行结束后再退出


接下来改造端口扫描的代码,采用协程的方式实现:

import socket
import time
import gevent
from gevent import monkey
from gevent.pool import Pool
monkey.patch_all()
def scan_port(host, port):
    sk = socket.socket()
    sk.settimeout(0.5)
    conn_result = sk.connect_ex((host, port))
    if conn_result == 0:
        print(f'服务器{host}的{port}端口已开放')
    sk.close()
def gevent_scan_host(host):
    # 8.129.162.225
    start_time = time.time()
    run_list = []
    g = Pool(200)   # 限制协程并发数量,单线程的,不要设置太大
    for port in range(0, 65536):
        run_list.append(g.spawn(scan_port, host, port))
    gevent.joinall(run_list)
    end_time = time.time()
    print(f'耗时:{end_time-start_time}')
host = input('请输入服务器ip地址:')
gevent_scan_host(host)

相关文章都是边学习边整理的笔记,如有错误,欢迎指正。如需进学习交流群,或者互相交流,文章催更,商务合作等,可添加微信xiaobotester ,记得备注一下。


相关文章
|
5月前
|
存储 缓存 测试技术
理解Python装饰器:简化代码的强大工具
理解Python装饰器:简化代码的强大工具
|
6月前
|
程序员 测试技术 开发者
Python装饰器:简化代码的强大工具
Python装饰器:简化代码的强大工具
266 92
|
5月前
|
机器学习/深度学习 编解码 Python
Python图片上采样工具 - RealESRGANer
Real-ESRGAN基于深度学习实现图像超分辨率放大,有效改善传统PIL缩放的模糊问题。支持多种模型版本,推荐使用魔搭社区提供的预训练模型,适用于将小图高质量放大至大图,放大倍率越低效果越佳。
427 3
|
6月前
|
Go 调度 Python
Golang协程和Python协程用法上的那些“不一样”
本文对比了 Python 和 Go 语言中协程的区别,重点分析了调度机制和执行方式的不同。Go 的协程(goroutine)由运行时自动调度,启动后立即执行;而 Python 协程需通过 await 显式调度,依赖事件循环。文中通过代码示例展示了两种协程的实际运行效果。
290 7
|
6月前
|
人工智能 自然语言处理 安全
Python构建MCP服务器:从工具封装到AI集成的全流程实践
MCP协议为AI提供标准化工具调用接口,助力模型高效操作现实世界。
1217 1
|
6月前
|
传感器 数据采集 监控
Python生成器与迭代器:从内存优化到协程调度的深度实践
简介:本文深入解析Python迭代器与生成器的原理及应用,涵盖内存优化技巧、底层协议实现、生成器通信机制及异步编程场景。通过实例讲解如何高效处理大文件、构建数据流水线,并对比不同迭代方式的性能特点,助你编写低内存、高效率的Python代码。
281 0
|
5月前
|
数据采集 网络协议 API
协程+连接池:高并发Python爬虫的底层优化逻辑
协程+连接池:高并发Python爬虫的底层优化逻辑
|
5月前
|
算法 安全 数据安全/隐私保护
Python随机数函数全解析:5个核心工具的实战指南
Python的random模块不仅包含基础的随机数生成函数,还提供了如randint()、choice()、shuffle()和sample()等实用工具,适用于游戏开发、密码学、统计模拟等多个领域。本文深入解析这些函数的用法、底层原理及最佳实践,帮助开发者高效利用随机数,提升代码质量与安全性。
1006 0
|
6月前
|
API 数据安全/隐私保护 Python
拼多多批量上架软件, 电商一键上货发布工具,python电商框架分享
多线程批量上传架构,支持并发处理商品数据 完整的拼多多API签名和token管理机制
Python---试除法求质数的三种方式对比
此三种方法都是基于试除法,即不断地尝试能否整除。比如要判断自然数 x 是否质数,就不断尝试小于 x 且大于1的自然数,只要有一个能整除,则 x 是合数;否则,x 是质数。
1794 0

推荐镜像

更多