delphi端口扫描源程序

{
  ------------------------------------------------
     本程序由“啊D”制作!
     QQ:9269563
     E-Mail:paf@163.net
     主页:Http://coold.cn99.com
     制作于:2002.8.27

  **你可以随意修改代码! 但在转载时请保留此声名!**
  ------------------------------------------------
}
unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Buttons, StdCtrls, ComCtrls,winsock,SearchPortThread, Spin;

type
  TForm1 = class(TForm)
    M1: TMemo;
    Port1: TEdit;
    Port2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Search: TSpeedButton;
    SB1: TStatusBar;
    MaxThread: TSpinEdit;
    Label4: TLabel;
    IP: TComboBox;
    AboutButton: TSpeedButton;
    procedure SearchClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure AboutButtonClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    procedure Search_ST;
    procedure ThreadDone(Sender: TObject);
    procedure Search_Exit;
    function HostNameToIP(S: string): DWord;
    procedure AddComboBox(CB: TcomboBox);
    procedure SearchOK;
      { Private declarations }
  public
    ThreadList: array of TSearchPortThread;   //线程数组
    Portlist:Tlist; //线程要用到的Strings
    PortIndex:integer; //正在处理的端口号
    MaxPort,MinPort:integer; //保存最大和最小的端口号的变量
    addr:Tsockaddr; //
    About:string; //关于
    StopThread:boolean; //停止线程标记

    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{
=============================
=          自定义函数       =
=============================
}

//==== 开始扫描 ====
procedure TForm1.Search_ST();
var
i,j:integer;
Address: DWord;
begin
try
//-- 检测部分 --
Address := HostNameToIP(PChar(IP.text));// 检测IP是否有效!
if (Address = INADDR_NONE) then begin
    showmessage('输入的IP、域名无效或网络不通!');
    exit;
end;

if MaxThread.Value < 2 then begin //检测线程数
    showMessage('线程数请选择 2-300 之间的值!');
    exit;
end;

Maxport:=strtoint(port2.text); //最大端口号
Minport:=strtoint(port1.text); //最小端口号
PortIndex:=Minport;

if Minport > Maxport then begin
    showMessage('[开始端口]不能大于[结束端口]的值!');
    exit;
end;
//端口范围检测
if (minport < 1) or (minport >65535) or (Maxport < 1) or (Maxport >65535) then begin
    showMessage('输入数值超过了指定的范围!'#13#10'数值范围:1-65535');
    exit;
end;
//------扫描部分-------
search.Caption := '停止扫描';
search.tag :=1;
AddComboBox(IP); //把IP或域名加入列表!
m1.lines.Clear;
m1.Lines.Add('正在扫描: ' + ip.text + #13#10'[端口] | [说明]'#13#10'-------------------------------------');
m1.Update;
  SetLength(ThreadList,MaxThread.Value);  //创建 MaxThread.Value 个线程数组
  if (length(threadlist) >1) then j:=length(threadlist)-1;
  if (maxport-minport)<j then j:=maxport-minport;

  for i:=0 to j do
  begin
    addr.sin_family:=AF_INET; //
    addr.sin_addr.S_addr:=Address;  //地址
    addr.sin_port:=htons(PortIndex); //端口

    threadlist[i]:=TSearchPortThread.Create(m1,addr);  //创建线程1
    threadlist[i].OnTerminate :=ThreadDone; //线程处理完后要处理的事
    Portlist.Add(threadlist[i]);  //把线程加入 Portlist
    sb1.Panels[0].Text :=format('已扫描端口: %s',[inttostr(Portindex)]);
    PortIndex:=PortIndex+1;
end;
//出错处理代码
except
showMessage('出错了!');
end;
end;
//===== END =====


//==== 线程退出代码 ======
procedure TForm1.ThreadDone(Sender: TObject);
var
Index:integer;
begin
try

if (PortIndex >= maxport) and (StopThread=false) then begin
    SearchOK();
    StopThread:=true;
    exit;
end;
if (PortIndex > maxport) or (StopThread = true) then exit;

Index := PortList.IndexOf(Sender); //在Filst 中查找刚才的线程对象
PortList.Delete(Index);

addr.sin_port:=htons(portindex); //端口
threadlist[Index]:=TSearchPortThread.Create(m1,addr);  //创建线程1
threadlist[Index].OnTerminate :=ThreadDone; //线程处理完后要处理的事
Portlist.Add(threadlist[Index]);  //把线程加入 Portlist
sb1.Panels[0].Text :='已扫描端口: ' + inttostr(Portindex);
PortIndex:=PortIndex+1;
except //错误处理
//    sb1.Panels[0].Text :='程序出错[线程退出]!';
end;
end;
//===== END =====


//==== 停止扫描 =====
Procedure Tform1.Search_Exit;
var
i:integer;
temp:TSearchPortThread;
begin
try
 m1.Lines.Add('[ 用户中断 ]');
 sb1.Panels[0].Text :='正在关闭线程.....';
for i:=0 to portlist.Count  - 1 do
begin
    temp:=portlist.Items[i];
    temp.Terminate;  //结束线程
end;
      SearchOK(); //显示开始扫描
      StopThread:=true; //StopThread为真,为停止扫描

except //错误处理
//   sb1.Panels[0].Text :='程序出错[停止扫描]!';
end;
end;
//===== END =====

// ===== 扫描完成 =========
procedure Tform1.SearchOK();
begin
      search.Caption :='开始扫描';
      search.Enabled :=true;
      search.tag:=0;
      sb1.Panels[0].Text :='扫描完成';
      m1.Lines.Add('-------------------------------------'#13#10'扫描完成!');
      portlist.Free;//释放PortList的内存空间
end;
//==== END ====

//==== 域名、IP自动转为IP ====
function TForm1.HostNameToIP(S:string):DWord;
const
  INADDR_NONE = $FFFFFFFF;
var
Host:pHostent;
Address:DWord;
begin
Address := inet_addr(PChar(S));
if (Address = INADDR_NONE) then begin
   Host:=GetHostByName(Pchar(S));
   if Host = nil then begin
        HostNameToIP:=INADDR_NONE;
        exit;
   end
   else begin
        hostNametoip:=longint(pointer(Host^.h_addr_list^)^);
        exit;
   end;
end
else begin
  HostNameToIP:=Address;
  exit;
end;
end;
//==== END ====

//==== 自动把ComboBox控件的内容里没有的内容加入列表中 =====!
procedure Tform1.AddComboBox(CB:TcomboBox);
var
a :integer;
begin
    a:=CB.Items.IndexOf(CB.Text);
    if a=-1 then CB.Items.Add(CB.Text);
end;
//== END ===

// ◎◎◎ 自定义函数 END ◎◎◎

 


{
=============================
          控件部分
==============================
}

//==== Search按钮 =====
procedure TForm1.SearchClick(Sender: TObject);
begin
if search.tag =0 then begin
    portlist:=Tlist.Create; //创建Tstring
    Search_ST(); //开始
    StopThread:=false; //停止为假时,为扫描
end
else begin
    Search_Exit(); //停止
end;
end;
//===== END =====


//===== Form 创建 =====
procedure TForm1.FormCreate(Sender: TObject);
var
Wsadata:Twsadata;
begin
WSAStartup(Makeword(2,0),Wsadata);//
About:=m1.Text; //把简介内容保存到About变量中
end;
//===== END =====


//===== Form 退出 ======
procedure TForm1.FormDestroy(Sender: TObject);
begin
//PortList.free; //释放PortList的内存空间
WSAcleanUP;//
end;
//===== END ======


//===== 当按‘回车’、‘Esc’键时的动作 ======
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (key =#13) and (search.Tag=0) then  SearchClick(Sender); //开始扫描
if (key =#27) and (search.Tag=1) then  SearchClick(Sender); //停止扫描
end;
//===== END ======

 

//==== 关于 =====
procedure TForm1.AboutButtonClick(Sender: TObject);
begin
showMessage(About +
'地址:深圳市龙岗区坪山镇石井太阳村'#13#10#13#10 +
'注:'#13#10 +
'本软件为免费软件,对使用本软件产生'#13#10 +
'的后果,本人不承担任何的责任!'#13#10#13#10 +
'本程序用Delphi编写,如要源码,请和作者联系!'#13#10#13#10 +
'制作时间: 2002年8月27日'
);
//m1.Text:=About;
end;
//==== END =====

//====== 窗口居中 ======
procedure TForm1.FormShow(Sender: TObject);
begin
     Left := (Screen.Width - Width) div 2;
     Top := (Screen.Height - Height) div 2;
end;
//===== END ====

// ◎◎◎ 控件部分 END ◎◎◎

end.

 

 

 


____________________________________________________________________________________________

 

果你写扫描程序可千万不要直接去连接,应该使用别的链接方法,否则你的踪迹会被别人
发现.例如使用sys扫描或者fin扫描:
我给你异步socket的api代码:
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,WInSock, ExtCtrls;

const WM_SOCKET=WM_USER+1;   //socket消息

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Panel1: TPanel;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    Sockhd : integer;   //socket句柄
    Serv_Addr : Tsockaddr;//目标地址

  procedure SockEvent(var msg: Tmessage);message WM_SOCKET;   //处理cocket消息
  procedure DspMsg(msg : string);   //显示信息
    { Private declarations }
  public
    { Public declarations }
  end;

  Form1: TForm1;

implementation
{$R *.DFM}

function lookup_hostname(const hostname:string):longint;  //把域名转化成IP地址
var
  RemoteHost : PHostEnt;  (* no, don't free it! *)
  ip_address: longint;
begin
  ip_address:=-1;
  try
    if hostname='' then
      begin  (* no host given! *)
        lookup_hostname:=ip_address;
        EXIT;
       end
    else
      begin
        ip_address:=Winsock.Inet_Addr(PChar(hostname));  (* try a xxx.xxx.xxx.xx first *)
        if ip_address=SOCKET_ERROR then begin
        RemoteHost:=Winsock.GetHostByName(PChar(hostname));
        if (RemoteHost=NIL) or (RemoteHost^.h_length<=0) then
          begin
            lookup_hostname:=ip_address;
            EXIT;  (* host not found *)
          end
        else
          ip_address:=longint(pointer(RemoteHost^.h_addr_list^)^);
      end;
      end;
   except
    ip_address:=-1;
  end;
  lookup_hostname:=ip_address;
end;

procedure TFOrm1.DspMsg(msg: string);
begin
 memo1.Lines.Add(msg+'...');
 if Memo1.Lines.Count>200 then Memo1.Lines.Delete(0);
end;

procedure TForm1.SockEvent(var msg : tmessage);  //处理socket消息
begin
 case msg.LParam of
  FD_READ: begin    //标识可以读数据,当然肯定已经链接上了
    dspmsg('可以读取数据');
    //do what you want do
  end;

  FD_WRITE: begin
    dspmsg('可以发送数据');
    //do what you want do
  end;

  FD_ERROR: begin
    dspmsg('发生错误');
     //如果你是客户端,则应该是连接不上,即端口没有开
  end;

  FD_CLOSE: Begin
    dspmsg('服务器断开连接');
    //对方关闭连接
  end;

  FD_CONNECT: begin
    dspmsg('连结上服务器');
    //表示对方端口开放
  end;

  FD_ACCEPT: begin
    dspmsg('接收一个请求');
   //这个消息只有服务端可能出现
  end;
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
 var  wsaData:TwsaData;
begin                 //启动winsock动态链接库
  if WSAStartup (makeword(2,2), wsaData)<>0 then begin
    messagebox(application.handle,'无法启动winsock动态连接库!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
    Application.Terminate;
  end; 
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin    //关闭dll
 WSACleanup;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Sockhd := socket(AF_INET,SOCK_STREAM,0);  //创建socket句柄
 if Sockhd<0 then begin
   messagebox(application.handle,'无法创建句柄!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
   exit;
 end;
  Serv_addr.sin_addr.s_addr:= lookup_hostname(edit1.Text);  //主机名
  Serv_addr.sin_family := PF_INET;
  Serv_addr.sin_port := htons(23);      //any port you want to connect

  if WSAAsyncSelect(Sockhd,Form1.handle,WM_SOCKET,FD_ACCEPT or FD_CONNECT or FD_CLOSE or  FD_READ or FD_WRITE)=SOCKET_ERROR
  then begin
   messagebox(application.handle,'无法创建句柄!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
   exit;
  end;   //异步socket
  connect(sockhd,serv_addr,sizeof(serv_addr));  //连接,结果会在前面的处理函数处理
end;

end.
相信应该可以满足你的要求
 
 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DELPHI串口编程剖析 1 第一章 背景知识 3 1. 概述 3 2. 什么是接口? 3 3. 接口分类. 3 4. 为什么需要I/O接口? 3 5. I/O接口的功能 4 6. I/O接口的通信方式 5 7. I/O接口的分类 5 8. 串口的分类 8 9. 串口通信分类 11 10. 奇偶校验 12 第二章 串口通信编程简介 13 1. 串口的通信编程流程 13 2. Unix平台下对串口进行开发的方法 13 3. Windows平台下对串口进行开发的方法 13 第三章 使用DELPHI工具进行串口通信编程 15 第四章 串口编程的调试及其相关工具 27 串口通信编程剖析 第一章 背景知识 1. 概述 串口是计算机上I/O接口的一种,要掌握串口通信编程的相关知识,必须先了解I/O接口的相关知识。 I/O接口是接口的一种。 2. 什么是接口? 众所周知计算机是由CPU,存储器,外部终端设备组成. 接口就是用于CPU与外部设备、存储器的连接和数据交换的设备。 3. 接口分类. 广义的计算机接口有二种,见下表: 类別 用途 电路实现复杂性 存储器接口: 用于CPU与外部设备、存储器的连接 简单 I/O接口 数据交换 复杂 习惯上说到接口只是指I/O接口。本文沒作特別介绍的地方都叫I/O接口. 4. 为什么需要I/O接口? 计算机的外围设备品种繁多,几乎都采用了机电传动设备,因此,CPU在与I/O设备进行数据交换时存在以下问题: 速度不匹配: I/O设备的工作速度要比CPU慢许多,而且由于种类的不同,他们之间的速度差异也很大,例如硬盘的传输速度就要比打印机快出很多。 时序不匹配: 各个I/O设备都有自己的定时控制电路,以自己的速度传 输数据,无法与CPU的时序取得统一。 信息格式不匹配: 不同的I/O设备存储和处理信息的格式不同,例如可以分为串行和并行两种;也可以分为二进制格式、ACSII编码和BCD编码等。 信息类型不匹配: 不同I/O设备采用的信号类型不同,有些是数字信号,而有些是模拟信号,因此所采用的处理方式也不同。    基于以上原因,CPU与外设之间的数据交换必须通过I/O接口来完成。 5. I/O接口的功能 通常I/O接口有以下一些功能: 1)设置数据的寄存、缓冲逻辑,以适应CPU与外设之间的速度 差异,接口通常由一些寄存器或RAM芯片组成,如果芯片足够大还可以实现批量数据的传输; 2)能够进行信息格式的转换,例如串行和并行的转换; 3)能够协调CPU和外设两者在信息的类型和电平的差异,如电平 转换驱动器、数/模或模/数转换器等;    4)协调时序差异;    5)地址译码和设备选择功能;    6)设置中断和DMA控制逻辑,以保证在中断和DMA允许的情况下产生中断和DMA请求信号,并在接受到中断和DMA应答之后完成中断处理和DMA传输。    6. I/O接口的通信方式 CPU通过接口对外设进行控制的方式有以下几种: 1)程序查询方式 这种方式下,CPU通过I/O指令询问指定外设当前的状态,如果外设 准备就绪,则进行数据的输入或输出,否则CPU等待,循环查询。 这种方式的优点是结构简单,只需要少量的硬件电路即可,缺点是由 于CPU的速度远远高于外设,因此通常处于等待状态,工作效率很 低。 2)中断处理方式 在这种方式下,CPU不再被动等待,而是可以执行其他程序,一旦 外设为数据交换准备就绪,可以向CPU提出服务请求,CPU如果响 应该请求,便暂时停止当前程序的执行,转去执行与该请求对应的 服务程序,完成后,再继续执行原来被中断的程序。   中断处理方式的优点是显而易见的,它不但为CPU省去了查询外设 状态和等待外设就绪所花费的时间,提高了CPU的工作效率,还满 足了外设的实时要求。但需要为每个I/O设备分配一个中断请求号 和相应的中断服务程序,此外还需要一个中断控制器(I/O接口芯 片)管理I/O设备提出的中断请求,例如设置中断屏蔽、中断请求 优先级等。此外,中断处理方式的缺点是每传送一个字符都要进行 中断,启动中断控制器,还要保留和恢复现场以便能继续原程序的 执行,花费的工作量很大,这样如果需要大量数据交换,系统的性 能会很低。 3)DMA(直接存储器存取)传送方式 DMA最明显的一个特点是它不是用软件而是采用一个专门的控制 器来控制内存与外设之间的数据交流,无须CPU介入,大大提高 CPU的工作效率。   在进行DMA数据传送之前,DMA控制器会向CPU申请总线控 制 权,CPU如果允许,则将控制权交出,因此,在数据交换时, 总线控制权由DMA控制器掌握,在传输结束后,DMA控制器将 总线控制权交还给CPU。    7. I/O接口的分类 7.1. 并行接口   目前,计算机中的并行接口主要作为打印机端口,接口使用的不再是36针接头而是25针D形接头。所谓“并行”,是指8位数据同时通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,容易出错。   现在有五种常见的并口:4位、8位、半8位、EPP和ECP,大多数PC机配有4位或8位的并口,许多利用Intel386芯片组的便携机配有EPP口,支持全部IEEE1284并口规格的计算机配有ECP并口。   标准并行口4位、8位、半8位:   4位口一次只能输入4位数据,但可以输出8位数据;8位口可以一次输入和输出8位数据;半8位也可以。   EPP口(增强并行口):由Intel等公司开发,允许8位双向数据传送,可以连接各种非打印机设备,如扫描仪、LAN适配器、磁盘驱动器和CDROM 驱动器等。   ECP口(扩展并行口):由Microsoft、HP公司开发,能支持命令周期、数据周期和多个逻辑设备寻址,在多任务环境下可以使用DMA(直接存储器 访问)。   目前几乎所有的586机的主板都集成了并行口插座,标注为 Paralle1或LPT1,是一个26针的双排针插座。 7.2. 串行接口   计算机的另一种标准接口是串行口,现在的PC机一般至少有两个串行口COM1和COM2。串行口不同于并行口之处在于它的数据和控制信息是一位接一位串行地传送下去。这样,虽然速度会慢一些,但传送距离较并行口更长,因此长距离的通信应使用串行口。通常COM1使用的是9针D形连接器,而COM2有些使 用的是老式的DB25针连接器。    7.3. 磁盘接口 1)IDE接口   IDE接口也叫做ATA端口,只可以接两个容量不超过528M的硬盘驱动器,接口的成本很低,因此在386、486时期非常流行。但大多数IDE接口不支持DMA数据传送,只能使用标准的PCI/O端口指令来传送所有的命令、状态、数据。几乎所有的586主板上都集成了两个40针的双排针IDE接口插座,分别标注为IDE1和IDE2。 2)EIDE接口 EIDE接口较IDE接口有了很大改进,是目前最流行的接口。 首先,它所支持的外设不再是2个而是4个了,所支持的设备除了硬盘,还包括CD-ROM驱动器磁盘备份设备等。   其次,EIDE标准取消了528MB的限制,代之以8GP限制。   第三,EIDE有更高的数据传送速率,支持PIO模式3和模式4标准。    7.4. SCSI接口   SCSI(SmallComputerSystemInterface)小计算机系统接口,在做图形处理和网络服务的计算机中被广泛采用SCSI接口的硬盘。除了硬盘以外,SCSI接口还可以连接CD-ROM驱动器、扫描仪和打印机等,它具有以下特点:   *可同时连接7个外设;   *总线配置为并行8位、16位或32位;   *允许最大硬盘空间为8.4GB(有些已达到9.09GB);   *更高的数据传输速率,IDE是2MB每秒,SCSI通常可以达到5MB每秒,FASTSCSI(SCSI-2)能达到10MB每秒,最新的SCSI-3甚至能够达到40MB每秒,而EIDE最高只能达到16.6MB每秒;   *成本较IDE和EIDE接口高很多,而且,SCSI接口硬盘必须和SCSI接口卡配合使用,SCSI接口卡也比IED和EIDE接口贵很多。   *SCSI接口是智能化的,可以彼此通信而不增加CPU的负担。在IDE和EIDE设备之间传输数据时,CPU必须介入,而SCSI设备在数据传输过程中起主动作用,并能在SCSI总线内部具体执行,直至完成再通知CPU。   

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值