port_segmentport;
port.dest=dest_ip[j];
port.min_port=i*SEG_LEN+1;
/*thelastsegment*/
if(i==(THREAD_NUM-1))
port.max_port=MAX_PORT;
else
port.max_port=port.min_port+SEG_LEN-1;
(3):
创建线程,开始扫描
if(pthread_create(&thread[i],NULL,scan,(void*)&port)!
=0)
{
perror("pthread_createfailed\n");
free(thread);
exit(-2);
}
(4):
释放创建的资源
free(pthread);
下图是实现该过程的流程图:
根据以上思路我们就可以编程来实现多线程的端口扫描器了
(1):
打开虚拟机,在Linux下的VI编辑器中编写服务器端程序tcpscanner.c
(2)使用命令gcc-otcpscannertcpscanner.c-g-lpthread编译;
(3):
执行命令:
./tcpscanner127.0.0.110.0.0.310.0.0.234
(4)通过观察程序执行的结果,发现程序很好的完成了功能,这样我们也就完成了第二个实验。
(接上)
实验内容(算法、程序、步骤和方法)
附试验源代码:
mypopen.c
//tcpserver.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePORT8900
#defineBUFSIZE2048
void*start_routine(void*arg);//声明线程处理函数
intexecute(char*command,char*buf)
{
FILE*fp;
intcount;
charcommandbuf[2056];
if((NULL==command)||(NULL==buf))
{
perror("commandorbufisempty\n");
return-1;
}
count=0;
memset(commandbuf,0,2056);
strcat(commandbuf,"sh-c");
strcat(commandbuf,command);
fprintf(stderr,"thecommandis%s\n",commandbuf);
if(NULL==(fp=popen(commandbuf,"r")))
{
perror("createpipeerror\n");
return-1;
}
while((count<2047)&&(EOF!
=(buf[count++]=fgetc(fp))));
buf[count-1]='\0';
returncount;
}
intmain()
{
intthread;
intsockfd;
intconn_sock;
charsendbuf[BUFSIZE];
charrecvbuf[BUFSIZE];
intsendnum=0;
intrecvnum=0;
intlength=0;
structsockaddr_inclient;
structsockaddr_inserver;
intopt;
intcnt;
/*Thefirststage:
INITILIZE*/
memset(&client,0,sizeof(client));
memset(&server,0,sizeof(server));
memset(sendbuf,0,BUFSIZE);
memset(recvbuf,0,BUFSIZE);
length=0;
sockfd=-1;
conn_sock=-1;
opt=SO_REUSEADDR;
/*Thesecondstage:
createlistensocket*/
if(-1==(sockfd=socket(AF_INET,SOCK_STREAM,0)))
{
perror("createsocketerror\n");
return-1;
}
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
/*Thethirdstage:
bindsocket*/
server.sin_family=AF_INET;
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(PORT);
if(-1==bind(sockfd,(structsockaddr*)&server,sizeof(server)))
{
perror("bindsocketerror\n");
close(sockfd);
return-1;
}
/*Thefourthstage:
listensocket*/
if(-1==listen(sockfd,10))
{
perror("listensocketerror\n");
close(sockfd);
return-1;
}
/*Thefifthstage:
creatconnectsocket*/
while
(1)
{
if(-1==(conn_sock=accept(sockfd,(structsockaddr*)&client,&length)))
{
perror("threeshakehandserror\n");
close(sockfd);
return-1;
}
//调用线程函数
if(pthread_create(&thread,NULL,(void*)start_routine,(void*)conn_sock))
{
perror("Pthread_create()error");
exit
(1);
}
}
}
//线程函数的实现
void*start_routine(void*arg)
{
intconn_sock=arg;
intsockfd;
charsendbuf[BUFSIZE];
charrecvbuf[BUFSIZE];
intsendnum;
intrecvnum;
intlength;
intopt;
intcnt;
while
(1)
{
close(sockfd);
memset(recvbuf,0,BUFSIZE);
memset(sendbuf,0,BUFSIZE);
if(0>=(recvnum=read(conn_sock,recvbuf,BUFSIZE)))
{
perror("thecommucationerror\n");
close(conn_sock);
close(sockfd);
return-1;
}
recvbuf[recvnum]='\0';
fprintf(stderr,"thecommandis:
%s\n",recvbuf);
if(0==strcmp(recvbuf,"quit"))
{
fprintf(stderr,"theclientisquit\n");
close(conn_sock);
break;
}
if(1>=(cnt=execute(recvbuf,sendbuf)))
{
sprintf(sendbuf,"theinvalidcommand,pleasetryagain\n");
}
fprintf(stderr,"theresultis\n%s",sendbuf);
if(0>=(sendnum=write(conn_sock,sendbuf,strlen(sendbuf))))
{
perror("thecommucationerror\n");
close(conn_sock);
return-1;
}
}
close(sockfd);
}
tcpscanner.c
#include
#include
#include
#include
#include
#include
#include
#include
#defineSCANLENGTH655//每个线程分配655个端口
#defineTHREADNUM100//100个线程
#defineSTART_PORT1//起始端口号
#defineEND_PORT65535//结束端口号
structPort//定义端口结构体
{
intscan_minPort;
intscan_maxPort;
char*IP;
}Port;
voidprint_usage(char*str);//打印出错信息
void*scan(void*arg);//声明扫描函数
intmain(intargc,char*argv[])
{
intret;
structsockaddr_inserver;
structservent*serve;
if(argc<2)
{
print_usage(argv[0]);
exit
(1);
}
//创建100个线程描述符
pthread_t*thread;
thread=(pthread_t*)malloc(THREADNUM*sizeof(pthread_t));
intj;
inti;
//为每个线程创建扫描的分工
for(j=1;j{
for(i=0;i{
structPort*port=(structPort*)malloc(sizeof(structPort));
port->IP=argv[j];
port->scan_minPort=i*SCANLENGTH+1;
if(i==(THREADNUM-1))
port->scan_maxPort=END_PORT;
else
port->scan_maxPort=port->scan_minPort+SCANLENGTH-1;
//创建线程,开始扫描
if(pthread_create(&thread[i],NULL,(void*)scan,(void*)port)!
=0)
{
perror("thead_createerror!
\n");
free(thread);//释放创建的资源
exit(-1);
}
}
}
return0;
}
voidprint_usage(char*str)
{
printf("thecommand%susageis:
\n",str);
printf("%sIP_ADDRESSIP_ADDRESSIP_ADDRESS\n",str);
}
//扫描函数的实现
void*scan(void*arg)
{
pthread_detach(pthread_self());
intsockfd;
intret;
intopt=SO_REUSEADDR;
structsockaddr_inserver;
structservent*serve;
char**name;
structPort*port=(structPort*)arg;
intstart;
intend;
intscanPort;
start=port->scan_minPort;
end=port->scan_maxPort;
for(scanPort=start;scanPort!
=end;scanPort++)
{
if(-1==(sockfd=socket(AF_INET,SOCK_STREAM,0)))
{
perror("socketfailed!
\n");
exit(-1);
}
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
memset(&server,0,sizeof(server));
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr(port->IP);
server.sin_port=htons(scanPort);
ret=connect(sockfd,(structsockaddr*)&server,sizeof(structsockaddr))+1;
if(ret==0)
{
close(sockfd);
continue;
}
elseif(ret==1)
{
if((serve=getservbyport(htons(scanPort),"TCP"))==NULL)
printf("IP=%sscanPort=%dUnknownservice\n",port->IP,scanPort);
else
{
printf("IP=%sscanPort=%ds_name=%s\n",port->IP,scanPort,serve->s_name);
for(name=serve->s_aliases;*name!
=NULL;name++)
printf("IP=%sscanPort=%daliasenameis%s\n",port->IP,scanPort,*name);
}
close(sockfd);
}
}
}
数据记录
和计算
详细见上面
结论
(结果)
(1)利用多线程技术能实现并发服务器,且比多进程的实现的方式更有效
(2)利用多线程技术能加强端口扫描的功能。
小结
通过本实验,我掌握了:
1)进一步熟悉了Linux下C语言程序开发的过程;
2)了解了一些基本的线程函数
3)掌握了如何利用多线程实现并发服务器
4)会编写多线程端口扫描程序
目前我存在的问题有:
对线程的函数掌握的不是很熟练
指导老师评议
成绩评定:
指导教师签名:
实验报告说明
专业实验中心
实验名称要用最简练的语言反映实验的内容。
如验证某程序、定律、算法,可写成“验证×××”;分析×××。
实验目的目的要明确,要抓住重点,可以从理论和实践两个方面考虑。
在理论上,验证定理、公式、算法,并使实验者获得深刻和系统的理解,在实践上,掌握使用实验设备的技能技巧和程序的调试方法。
一般需说明是验证型实验还是设计型实验,是创新型实验还是综合型实验。
实验环境实验用的软硬件环境(配置)。
实验内容(算法、程序、步骤和方法)这是实验报告极其重要的内容。
这部分要写明依据何种原理、定律算法、或操作方法进行实验,要写明经过哪几个步骤。
还应该画出流程图(实验装置的结构示意图),再配以相应的文字说明,这样既可以节省许多文字说明,又能使实验报告简明扼要,清楚明白。
数据记录和计算指从实验中测出的数据以及计算结果。
结论(结果)即根据实验过程中所见到的现象和测得的数据,作出结论。
小结 对本次实验的体会、思考和建议。
备注或说明可写上实验成功或失败的原因,实验后的心得体会、建议等。
注意:
∙实验报告将记入实验成绩;
∙每次实验开始时,交上一次的实验报告,否则将扣除此次实验成绩。