你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 专家论坛
单进程tracert.exe按多线程ping.exe运行
 

一、概述pingtracert命令

    Win 9x的网络命令中,ping.exetracert.exeDOS环境下的命令,前者检测本机H到远程主机R的连通性,后者显示HR的连接路由。

    两者指向R的参数,可为IP地址,211.68.32.1,也可为域名,e250.biti.edu.cn.算法,都是从HR发送要求回应的ICMP试探包p,静等回应,然后,ping作出简单连通与否结论,tracert作出详细路经节点结论。

    两者也可将上述参数,置为127.0.0.1"系统特性"中的机器名,本机自连.

    ICMPIP层的协议,此层只能建立无连接的传输系统,不保证数据包能到达目的地,或按发送顺序到达,不保证HR的每次连接,路经节点都相同。

   IP包的头部,含有H的源节点IP地址,R的目的节点IP地址.ICMP,再含IPINFOECHO结构:

typedef struct{

    u_char TTL; //Time To Live

    ...

}IPINFO;

typedef struct{

    ...

    u_long Status;  //IP status

    ...

}ECHO;

    IPINFOTTL,决定p能跨过的中途节点数(hob_step);ECHOStatus,值为0,表明到达R.

    遵守TCP/IP协议的网络节点,IP层进程,收到p时的动作是:

(1.1) 中途节点i捕到p,先对上述TTL,TTL=TTL-1,若新TTL值大于0,i就在与它相邻的物理节点中,选择p还未到过的某节点,向其传输带有新TTL值的p,使p不走回头路.若新TTL值等于0,i就向H回发不必回应的ICMP"超时"e,表明hob_step在中途耗尽,此包的源节点为i,目的节点为H,ECHO.Status0x2AFB

(1.2) R捕到p,同样向H回发e,此时,源节点变为R,ECHO.Status变为0.

    ping仅处理一次回应:根据eECHO.Status是否为0,作出连通与否结论。

    tracert处理多次回应:ECHO.Status不为0e,记下发出e的各中途节点i,直至ECHO.Status变为0,H已发出最大hob_step=255,仍连不上R,这时,全面试探才算完,作出试探过程涉及的连接路由。

二、单进程tracert.exe化为多线程ping.exe运行

    ping发出p,TTL值为最大值255.

    tracert第一次发出p,TTL1,每次收到e,就查ECHO.Status,0表明TTL太小,够不着目标,这时,它就做p上的TTL=TTL+1,使中途节点能多跨一个,如此发出hob_step递增的p,直至ECHO.Status变为0,p上的TTL超过255

    笔者在2k,试探163.com,执行批处理文件

time /t

tracert 163.com

time /t

花费2分钟,显出15行结论。

由此设想,把一个tracert进程的15TTL赋新值,改为顺序发出TTL=[1-15]的各工作线程Ci,它们都按ping的仅处理一次回应方式工作,都回发e包给主进程,然后自行终止,这样,主进程先记载来自Cie包结果Ei,再输出E1,E2,...,E15组成的连接路由。

ICMP.DLL的输出函数IcmpSendEcho,能检测HR的连通性,于是,笔者写出以下3特点的仿pingtracertping_tracert.c程序:

(2.1) ping,TTL值为255IPINFO结构作为参数,执行IcmpSendEcho,R发送要求回应的p,以实现ping的功能。

(2.2) tracert,第一次试探,生成IPINFO结构的TTL值从177个线程,各线程用自己的IPINFO结构作为参数,执行IcmpSendEcho,若某线程到达R,tracert完成,否则等这批线程终止后,记下这批生成的7个中途节点,再生成TTL值从8147个线程,各线程再执行IcmpSendEcho,如此下去,直至某线程到达R,或生成IPINFO结构的TTL值超过255

 

这样,单进程tracert,按一批7个多线程ping.exe运行.试探163.com,只费1分钟.

(2.3) IcmpSendEcho能在包中携带中西文数据,e,返回原数据.

    ping_tracert命令行参数为 (-ping|-tracert) host [data],其中-ping将单进程做ping,-tracert将多线程做tracert,host指向R,data是可选项,指向数据。

    ping_tracert的开发环境,要求VC6控制台项目的link,链入ws2_32.lib

三、运行实例:

ping_tracert -ping 127.0.0.1 abc,得结果

127.0.0.1 xyz Reply:abc

这里,xyz是笔者机器名,ip地址是211.68.35.239

ping_tracert -ping xyz "A 12",得结果

211.68.35.239 xyz Reply:A 12

ping_tracert -tracert 127.0.0.1 "多道 p",得结果

[1] 127.0.0.1 xyz Reply:多道 p

四、源文

#include <stdio.h>

#include <stdarg.h>

#include <winsock2.h>

typedef struct{

    u_char TTL;         //Time To Live

    u_char TOS;         //Type Of Service

    u_char Flags;           //IP flags

    u_char OptSz;           //Size of options data

    u_char FAR *Options;        //Options data buffer

}IPINFO,*p_IPINFO;

typedef struct{

    u_long Source;  //Source address

    u_long Status;  //IP status

    u_long RoundTime;   //Round trip time in milliseconds

    u_short DataSize;   //Reply data size

    u_short Reserved;   //Unknown

    void FAR *pData;    //Reply data buffer

    IPINFO ipinfo;  //Reply options

}ECHO,*p_ECHO;

//ICMP.DLL中的函数指针

HANDLE(WINAPI *p_create)();

BOOL(WINAPI *p_close)(HANDLE);

DWORD(WINAPI *p_jog)(HANDLE,DWORD,LPVOID,WORD,p_IPINFO,LPVOID,DWORD,DWORD);

HANDLE h_icmp;

//远程主机

DWORD host;

struct hostent FAR *p_hostent;

//线程数

#define TOTAL 7

//试探包指针数组

char *stuff[TOTAL];

//数据字节长,试探包字节长,ttl初值

u_char data_len,stuff_len,ttl=1;

//e的来源及可选数据.参变

u_long ECHO_msg(char ac,...){

p_ECHO p;

va_list vl;

struct in_addr dec;

    va_start(vl,ac);

    if(ac==2)

        printf("[%d]\t",va_arg(vl,short));

    p=va_arg(vl,p_ECHO);

    dec.S_un.S_addr=p->Source;

    //IP地址

    printf("%d.%d.%d.%d",

    dec.S_un.S_un_b.s_b1,

    dec.S_un.S_un_b.s_b2,

    dec.S_un.S_un_b.s_b3,

    dec.S_un.S_un_b.s_b4);

    p_hostent=gethostbyaddr((char *)&dec.S_un.S_addr,4,PF_INET);

    //显域名

    if(p_hostent)

        printf("\t%s",p_hostent->h_name);

    //显可选数据

    if(data_len)

        printf("\tReply:%.*s\n",p->DataSize,p->pData);

    putchar('\n');

    va_end(vl);

    //标志到达远程主机与否

    return p->Status;

}

//子线程执行体

DWORD sub_thread(void *p_arg){

u_char sub_thread_num;

IPINFO ipinfo;

    //取当前线程号

    sub_thread_num=*(u_char *)p_arg;

    memset(&ipinfo,0,sizeof(ipinfo));

    //置线程ttl

    ipinfo.TTL=ttl+sub_thread_num;

    //host发送stuff[sub_thread_num],999是超时值

p_jog(h_icmp,host,stuff[sub_thread_num],data_len,&ipinfo,stuff[sub_thread_num

],stuff_len,999);

    //终止线程

    ExitThread(0);

}

void main(int ac,char *av[]){

HMODULE h_dll;

WSADATA WSA;

u_char thread_no;

//线程参数及线程id数组

DWORD thread_argument[TOTAL],thread_id[TOTAL];

//线程句柄数组

HANDLE h_thread[TOTAL];

IPINFO ipinfo;

    if(ac<3){

        printf("(-ping|-tracert) host [data]");

        return;

    }

 

    //映射ICMP.DLL到本进程

    h_dll=LoadLibrary("ICMP.DLL");

    //取函数指针

    p_create=(HANDLE(WINAPI *)())

        GetProcAddress(h_dll,"IcmpCreateFile");

    p_close=(BOOL(WINAPI *)(HANDLE))

        GetProcAddress(h_dll,"IcmpCloseHandle");

    p_jog=(DWORD(WINAPI *)

        (HANDLE,DWORD,LPVOID,WORD,p_IPINFO,LPVOID,DWORD,DWORD))

        GetProcAddress(h_dll,"IcmpSendEcho");

    //使用ICMP.DLL各函数前,调用Winsock 1.1版的WSAStartup

    WSAStartup(0x101,&WSA);

    //解析形如211.68.32.1av[2]

    host=inet_addr(av[2]);

    if(host==INADDR_NONE){

        //解析形如e250.biti.edu.cnav[2]

        p_hostent=gethostbyname(av[2]);

        if(p_hostent)

            memmove(&host,p_hostent->h_addr,p_hostent->h_length);

        else{

            printf("Can't Resolve %s\n",av[2]);

            return;

        }

    }

    //建立IcmpSendEcho需要的句柄

    h_icmp=p_create();

    //若携带数据,就求数据字节长

    if(ac==4)

        data_len=strlen(av[3]);

    //求试探包字节长

    stuff_len=data_len+sizeof(ECHO);

    if(!strcmp("-ping",av[1])){//单线程执行ping

        memset(&ipinfo,0,sizeof(IPINFO));

        ipinfo.TTL=255;

        stuff[0]=malloc(stuff_len);

 

        //携带数据

        memmove(stuff[0],av[3],data_len);

        //host发送stuff[0]

p_jog(h_icmp,host,stuff[0],data_len,&ipinfo,stuff[0],stuff_len,999);

    //e包来源及数据,若未达远程主机,"unreachable"

        if(ECHO_msg(1,(p_ECHO)stuff[0]))

            printf("%s:unreachable",av[2]);

    }else{//多线程执行tracert

        //初始化线程参数数组

        for(thread_no=0;thread_no!=TOTAL;thread_no++)

            thread_argument[thread_no]=thread_no;

        for(;;){

        for(thread_no=0;thread_no!=TOTAL;thread_no++){

        //某线程TTL值超过255,则不再生成线程

                if(ttl+thread_no==256)

                    break;

                stuff[thread_no]=malloc(stuff_len);

                //携带数据

                memmove(stuff[thread_no],av[3],data_len);

                //创建子线程,参数是线程号

                h_thread[thread_no]=CreateThread(NULL,0,

(LPTHREAD_START_ROUTINE)sub_thread,&thread_argument[thread_no],0,&thread_id[thread_no]);

            }

            //等这批线程全终止

WaitForMultipleObjects(thread_no,h_thread,TRUE,INFINITE);

            for(ac=0;ac!=thread_no;ac++)

            //e包来源及数据,若有一线程到达远程主机,则不再显

if(!ECHO_msg(2,(short)ttl+ac,(p_ECHO)stuff[ac]))

                    break;

            //ECHO.Status变为0,TTL超过255,tracert完成

            if(ac!=thread_no || thread_no!=TOTAL)

                break;

            ttl+=TOTAL;

        }

    }

 

    //关闭

    p_close(h_icmp);

    //停用WS2_32.DLL

    WSACleanup();

    //解射

    FreeLibrary(h_dll);

}

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089