以前曾用VB6.0写过一个灌水工具,用了WinSock控件。不过我还是喜欢命令行的工具。最近正学习套接字,于是就用C重写了这个工具。功能比以前那个更大。用来学习HTTP协议或者用来灌水都是相当不错的(呵呵,别骂我...)
先发个截图
关于程序的使用方法,帮助里面有。按照老样子,开源:
//HTTP报文提交工具 By RedIce
//E-mail:redice@see.xidian.edu.cn
//http://redice.1.suhai.com.cn
#include <winsock2.h> //Winsock API头文件
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib") //Winsock API连接库文件
char http_data[6000];//http报文缓冲区
char recvbuf[200];//接收缓冲区
void usage();//函数声明-程序使用说明
void main(int argc,char *argv[])
{
char *ICMP_DEST_IP;//目标主机IP
FILE * fileopr;
WSADATA wsaData;
SOCKET sender;
char thecurrentpath[200];//当前程序所在的路径
struct sockaddr_in dest;
PHOSTENT hostinfo;//主机信息(域名->IP)
int n=1; //发送数据包次数
int i;
int ret;
int timeout=2000;//超时
int filesize;//HTTP报文文件大小
char httpfile[200];//HTTP报文所在的文件
int getreturn=1;/*是否回显服务器返回的数据
false表示不显示,true表示显示
当n>1时,getreturn强制为false
*/
//命令行参数处理
memset(httpfile,0,200);
if(1==argc)//如果只有默认的命令行参数 则给出程序说明 并退出程序
{
usage();
return;
}
else//如果有多个参数
{
for(i=1;i<=argc-1;i++)
{
if(strstr(argv[i],"-r"))
{
getreturn=1;
}
if(strstr(argv[i],"-t"))
{
n=atoi(argv[i+1]);
if(n<0)
{
printf("-n 参数必须大于0\n");
return;
}
i++;
}
if(strstr(argv[i],"-f"))
{
if(strlen(argv[i+1])>=200)
{
printf("指定的文件名太长!\n");
return;
}
strcpy(httpfile,argv[i+1]);
i++;
}
if(strstr(argv[i],"-?"))
{
usage();
return;
}
}
}
ICMP_DEST_IP=argv[argc-1];//取得域名(IP)
if(n>1)//如果-n参数大于1则不回显服务器返回的数据
{
getreturn=0;
}
//如果用户指定了http报文路径则读取文件中的内容,否则使用默认报文
memset(http_data,0,6000);
if(strlen(httpfile))
{
if(!strstr(httpfile,"\\"))//如果是当前路径
{
memset(thecurrentpath,0,200);
for(i=strlen(argv[0])-1;i>=0;i--)
{
if(*(argv[0]+i)=='\\') break;//如果找到'\则跳出'
}
memcpy(thecurrentpath,argv[0],i+1);
//判断当前路径最后一个字符是否为'\'
if(thecurrentpath[strlen(thecurrentpath)-1]!='\\')
{
thecurrentpath[strlen(thecurrentpath)]='\\';
}
strcat(thecurrentpath,httpfile);
memset(httpfile,0,200);
strcpy(httpfile,thecurrentpath);
}
//读取文件中的报文
fileopr=fopen(httpfile,"r");//以只读的方式打开文件
if(NULL==fileopr)
{
printf("打开文件失败,请检查文件的路径是否正确!%s\n",httpfile);
return;
}
//取得文件大小
if(fseek(fileopr,0,SEEK_END))
{
printf("计算文件大小失败!\n");
return;
}
filesize=ftell(fileopr);
if(filesize<=0||filesize>6000)
{
printf("文件大小有误(不能为空且不能大于6000Bytes)!\n");
return;
}
if(fseek(fileopr,0,SEEK_SET))
{
printf("计算文件大小失败!\n");
return;
}
if(!fread(http_data,sizeof(char),6000,fileopr))
{
printf("读取HTTP报文文件失败!\n");
return;
}
fclose(fileopr);//关闭打开的文件
}
else
{
//默认的报文
//GET / HTTP/1.1
//Accept: */*
//Accept-Language: zh-cn
//Host: 你输入的域名(IP地址)
//Connection: Keep-Alive
strcpy(http_data,"GET / HTTP/1.1\nAccept: */*\nAccept-Language: zh-cn\nHost: ");
strcat(http_data,ICMP_DEST_IP);
strcat(http_data,"\nConnection: Keep-Alive\n\n");
}
//套接字版本协商
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf("初始化套接字失败!\n");
return;
}
//域名解析
hostinfo=gethostbyname(ICMP_DEST_IP); //参数为需要解析的主机名
if(NULL==hostinfo)
{
printf("无法解析主机%s的IP地址!",ICMP_DEST_IP);
WSACleanup();
return;
}
else
{
ICMP_DEST_IP=inet_ntoa(*(struct in_addr*)*hostinfo->h_addr_list);
}
//创建流式套接字
sender=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET==sender)
{
printf("创建套接字失败!\n");
WSACleanup();
return;
}
//设置接收超时
if(SOCKET_ERROR ==setsockopt(sender,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout)))
{
printf("设置套接字超时失败!\n");
closesocket(sender);
WSACleanup();
return;
}
//填充目的地址结构体
dest.sin_family=AF_INET;
dest.sin_addr.S_un.S_addr =inet_addr(ICMP_DEST_IP);
dest.sin_port=htons(80);
if(SOCKET_ERROR==connect(sender,(SOCKADDR *) &dest,sizeof(dest)))
{
printf("连接目的主机失败!\n");
closesocket(sender);
WSACleanup();
return;
}
printf("提交报文:\n%s\n",http_data);
for(i=1;i<=n;i++)
{
if(SOCKET_ERROR==send(sender,http_data,strlen(http_data),0))
{
printf("发送数据出错!\n");
closesocket(sender);
WSACleanup();
return;
}
else
{
printf("已提交报文%d次\n",i);
}
}
if(getreturn)//接收服务器发送的数据
{
printf("\n服务器返回的报文:\n%s\n",recvbuf);
while(1)//循环接收数据
{ memset(recvbuf,0,200);
ret=recv(sender,recvbuf,200,0);
if(-1==ret)
break;//返回-1表示接收完毕
else
{
printf("%s",recvbuf);
}
}
}
printf("\n");
//关闭套接字
closesocket(sender);
WSACleanup();
return;
}
//程序使用说明
void usage()
{
printf("HTTP报文提交工具\n\n");
printf("By RedIce\n");
printf("E-mail:redice@see.xidian.edu.cn\n");
printf("http:\\redice.1.suhai.com.cn\n");
printf("Usage: SendHttp.exe [-n] [-r] [-f] 目的主机(域名/IP地址)\n");
printf("Options:\n\n");
printf(" -n 指定发送报文的次数,这个参数用来灌水很不错\n");
printf(" -r 如果有该参数 程序将显示服务器返回的报文信息\n");
printf(" 注意:如果-n参数指定的值大于1,-r将被忽略\n");
printf(" -f 指定HTTP数据包文所在的文件\n");
printf(" 注意:如果不指定该参数,程序将使用默认报文:GET / HTTP/1.1\n");
printf(" -? 显示该帮助信息\n\n");
}