在多线程调用 端口扫描中,如何处理 N个IP+N个Port的情况?我的笨方法是一个ip+端口 启动一个线程但总不能一次启动1千以上个线程运转的

cclq 2005-03-11 05:20:41
在多线程调用 端口扫描中,如何处理 N个IP+N个Port的情况?我的笨方法是一个ip+端口 启动一个线程但总不能一次启动1千以上个线程运转的吧?
如何处理?

用线程池,或者别的算法?
...全文
356 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
cclq 2005-03-28
  • 打赏
  • 举报
回复
我的想法好像不错,但是代码写起来复杂多了。思考中...
cclq 2005-03-28
  • 打赏
  • 举报
回复
间隔时间 是同一个IP+Port的每次扫描之间的 ,就比如:192.168.2.2:80 扫描 100次,每次扫描间隔为1秒,
梦想家大魔王 2005-03-28
  • 打赏
  • 举报
回复
要看你设置的那个间隔时间是每个IP+Port之间的还是同一个IP+Port的每次扫描之间的,我是把它理解成每个IP+Port之间的间隔了。你的想法不错,我前面大概也就是这个意思。有一点要注意,只有在多CPU的机器上使用多线程才能真正获得性能上的提升,而且创建、切换和销毁线程也是要消耗CPU时间的,要控制这个时间不要让它占太大的比例,在一个线程内循环执行多次要比在多个线程内各执行一次的效率高。
cclq 2005-03-28
  • 打赏
  • 举报
回复
根据 skyhero(天骄) 的提示,我现在整理一下自己的看法

管理类初始化200个工作线程(最好可以更改)
管理类接收命令信息,解析到一个公用的命令列表中(ClientDataSet)

这200个工作线程轮流执行这个命令列表中的扫描信息,比如有300个需要扫描的ip+Port,那么
这200个工作线程就执行那200个IP+Port一次,大概是200个工作线程执行一次后,其中的100个会重新再执行另外的100个ip+Port。
单个工作线程每执行1个ip+port后,进行同步扫描结果(扫描结果也是一个公用的ClientDataSet),同时该ip+port的扫描次数减少一(若是无限扫描次数另外考虑)



cclq 2005-03-28
  • 打赏
  • 举报
回复
我想是不是可以这樣:管理類啓動200個工作綫程等待StringList命令(相當于綫程池,StringList信息我解析后放到一個全局的ClientDataSet中),通過一種協作的方式輪流工作,這200個工作綫程 輪流全面 掃描完成一次后,再根據每個命令掃描次數信息判定是否中斷(去掉)這個掃描命令,每全面掃描一次,StringList的命令信息中的掃描次數就減少1,直到為0

這樣可行嗎?

代碼實現上能否給點提示?

很謝謝 skyhero(天骄)的無私參與 ,若不介意,我另開帖子共給你200分。
cclq 2005-03-24
  • 打赏
  • 举报
回复
领会中.....



请稍后.....
梦想家大魔王 2005-03-24
  • 打赏
  • 举报
回复
当扫描结束后要记得释放内存:
var
i: Integer;
AScanNode: TScanNode;
begin
with TheList.LockList do
try
for i := 0 to Count - 1 do
begin
AScanNode := TScanNode(Items[i]);
if AScanNode <> nil then AScanNode.Free;
end;
Clear;
finally
TheList.UnlockList;
end;
end;
梦想家大魔王 2005-03-24
  • 打赏
  • 举报
回复
管理类只负责接收参数、创建工作线程和统计最后的扫描结果,不需要为每个工作线程硬性指派工作。
保存IP和Port的列表可以由管理类和工作线程类共享,工作线程启动后可以自己从里面读取要扫描的IP和Port。用于保存扫描信息的数据结构,我觉得用一个自定义记录体或者类会更方便一些:
...
type
TScanNode = class(TObject)
strIP: string;
iPort: Integer;
iLoopCount: Integer;
iDelay: Integer;
end;
而且因为涉及到多线程同步问题,列表最好使用线程安全的TThreadList,当然在这里因为工作线程只从列表里读数据而不向列表里面写数据,使TList的话也不会有什么问题。
...
var
TheList: TThreadList; {全局变量}
...
{管理类接收外部参数以后}
var
AScanNode: TScanNode;
begin
AScanNode := TScanNode.Create;
with AScanNode do
begin
strIP := 传入的IP;
iPort := 传入的Port;
iLoopCount := 传入的扫描次数;
iDelay := 传入的间隔时间值;
end;
with TheList.LockList do
try
Add(AScanNode);
finally
TheList.UnlockList;
end;
...
end;
cclq 2005-03-24
  • 打赏
  • 举报
回复
skyhero(天骄) :
你好,按照你的意思我下面的命令信息应该在管理类中处理并分配到各个线程内(1个ip+N个端口)

管理類 負責接收一個StringList類型的命令信息(一次性接收可能5千个),格式如下:
'192.168.1.1 ; 21 ; 100 ; 1000' // StringList[0]
'192.168.1.1 ; 8080 ; 100 ; 1000' // StringList[1]
'192.168.1.1 ; 80 ; 100 ; 1000' // StringList[2]

'192.168.2.2 ; 8080 ; 100 ; 1000' // StringList[3]
'192.168.2.2 ; 808 ; 100 ; 1000' // StringList[4]

'192.168.2.5 ; 808 ; 100 ; 1000' // StringList[5]

.........

梦想家大魔王 2005-03-24
  • 打赏
  • 举报
回复
一个IP加一个端口号组成了列表中的一条记录,也就是一个完整的被扫描单位。设置一个全局整型变量P,工作线程每次都是取得StringList[P]处的这条记录,然后马上使P的值加一,这样另一个线程读取数据的时候得到的就是下一条记录了。
如果把IP、端口、扫描次数、间隔时间等信息都放进一个string里,那么你应该有自己的组合这些信息以及提取这些信息的自定义函数,具体怎么做要看你自己是怎么定义的。我感觉还是用记录体或者类来保存这些信息比较方便,不用费心思去处理这些字符串。
cclq 2005-03-24
  • 打赏
  • 举报
回复
还是有个问题不明白,下面的这些信息列表,如何甄别一个ip只启动一个线程?而且众多端口信息怎么获得?

工作线程取得StringList[0],[1],[2]

'192.168.1.1 ; 21 ; 100 ; 1000' // StringList[0]
'192.168.1.1 ; 8080 ; 100 ; 1000' // StringList[1]
'192.168.1.1 ; 80 ; 100 ; 1000' // StringList[2]

'192.168.2.2 ; 8080 ; 100 ; 1000' // StringList[3]
'192.168.2.2 ; 808 ; 100 ; 1000' // StringList[4]

'192.168.2.5 ; 808 ; 100 ; 1000' // StringList[5]
梦想家大魔王 2005-03-23
  • 打赏
  • 举报
回复
如果Port不是连续的,那么可以放在一个数组里。如果是连续的,你只需要保存这个连续范围的最大值和最小值。或者是分段连续的,你可以把需要跳过的端口号保存起来。甚至不需要接受传入的Port,因为一共就那么多个端口,从头遍历也不是不可行。

不必硬性规定每个线程负责扫描那些IP,只要线程完成一个IP的扫描后发现还有没扫描过的IP,那么就取得这个IP开始扫描。当然取得这个IP之后要立即把它标记为已扫描,避免其它工作线程重复扫描这个IP。
cclq 2005-03-23
  • 打赏
  • 举报
回复
skyhero(天骄):
谢谢。

IP保存在一个TStrings里面,那么,对应IP的N个端口放到哪儿?

一次创建N个线程,每个线程开始运行时都从IP列表中取得当前未开始扫描的第一个IP
///如何分配N个线程的IP?

梦想家大魔王 2005-03-23
  • 打赏
  • 举报
回复
极端的情况是创建一个工作线程只扫描一个IP+Port的组合,但一般情况就是一个工作线程要负责若干个IP+Port的组合的扫描。就像蚂蚁搬家,要搬的东西很多,但蚂蚁数量有限,只好一趟一趟搬,搬完为止。
梦想家大魔王 2005-03-23
  • 打赏
  • 举报
回复
一次性创建大量的工作线程不是一个好主意,可能不仅不会获得性能上的提高,搞不好还有反效果。创建出上千个工作线程,估计只有一些大型的服务器程序需要那么做。
你的意思是不同的IP需要扫描的端口可能不一样吧?按照你提供的格式,你可以在管理类中设置一个属性MaxThreadCount: Integer;用来控制一次性创建的工作线程的最大数量。
如果传入的IP+Port的组合数据条目数量小于等于MaxThreadCount,那么就创建同样多的工作线程一对一地扫描,每个线程只工作一次;如果传入的数据条目数量超过了MaxThreadCount(这应该是一般情况),那么就创建MaxThreadCount个工作线程,每个线程都要循环工作直到所有工作都做完。
...
var
IPAndPortList: TStringList;
MaxThreadCount, {工作线程最大数目}
CurrentListID: Integer; {列表中第一条未扫描数据的序号}
...
{工作线程的执行部分}
procedure TScanThread.Excute;
var
IP: string; {当前要扫描的IP}
i,
Port, {当前要扫描的端口}
LoopCount: Integer; {扫描次数}
begin
while (not Terminated)
and (CurrentListID < IPAndPortList.Count) do
begin
{TODO: 从列表中读取一条数据,并且使CurrentListID的值加1,注意同步}
...
{TODO: 从读取的数据中取得IP, Port, LoopCount的值}
...
{开始对当前的IP+Port扫描}
for i := 0 to LoopCount - 1 do
begin
{TODO: 扫描}
...
{TODO: 保存或者输出扫描结果}
...
end;
...
Sleep(间隔时间);
end;
end;
cclq 2005-03-23
  • 打赏
  • 举报
回复
我正在寫一個可重用的掃描單元,單元内定義了一個掃描管理類和一個掃描綫程類

管理類 負責接收一個StringList類型的命令信息,格式如下:
'192.168.1.1 ; 21 ; 100 ; 1000' // StringList[0]
'192.168.1.1 ; 8080 ; 100 ; 1000' // StringList[1]
'192.168.2.2 ; 8080 ; 100 ; 1000' // StringList[2]
.....
ip port 扫描次数 间隔


管理類接受后,集中創建綫程實例執行。(我現在的做法是每一個Ip+Por創建一個綫程)集中創建綫程的時候把其指針記錄到一個StringList中,然後集中執行縣程。
問題是,若管理類接受的StringList.Count 數目很大的時候,内存就會不夠(大約1000個綫程佔用45M内存)

這樣做法行嗎?
能否給點解決此類問題的提示?
謝謝!
cclq 2005-03-23
  • 打赏
  • 举报
回复
skyhero(天骄) :

是这样的,怪我的问题还是没有说清楚:我正在写一个可重用的扫描单元,定义了一个管理类和一个
线程类。管理类负责接收扫描IP+port信息,是Stringlist的格式的如:
'192.168.1.1 ; 21 ; 100 ; 1000'
ip port 扫描次数 间隔



管理类接收N个扫描信息后,解析,然后Create 线程执行。(产生N个线程,记录其指针到管理类的Stringlist中,然后再执行)
现在的问题就是,总不能一个ip+port就create一个线程吧?
有没有什么好一点的解决办法?效率高点的,如线程池技术。

若一个ip +N个端口 用一个线程来扫描,那么线程类的写法就复杂些了,很想听听你的意见。
cclq 2005-03-23
  • 打赏
  • 举报
回复
skyhero(天骄) :

是这样的,怪我的问题还是没有说清楚:我正在写一个可重用的扫描单元,定义了一个管理类和一个
线程类。管理类负责接收扫描IP+port信息,是Stringlist的格式的如:
'192.168.1.1 ; 21 ; 100 ; 1000'
ip port 扫描次数 间隔



管理类接收扫描信息后,解析,然后Create 线程执行。
现在的问题就是,总不能一个ip+port就create一个线程吧?
有没有什么好一点的解决办法?
cclq 2005-03-22
  • 打赏
  • 举报
回复
就讨论成这样?
梦想家大魔王 2005-03-22
  • 打赏
  • 举报
回复
假设所有IP保存在一个TStrings里面,设置一个全局变量P: Integer,P是列表中当前还没有开始扫描的第一个IP的序号。
一次创建N个线程,每个线程开始运行时都从IP列表中取得当前未开始扫描的第一个IP,并且修改P的值让它指向下一个IP。线程内部扫描这个IP的所有Port。
扫描完一个IP的所有Port,如果还有未开始扫描的IP,就再取得一个开始扫描。如果发现所有IP都被扫描过了,则结束当前线程。
所有工作线程结束后,输出扫描结果。
加载更多回复(7)

5,379

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧