1、并发服务器II多线程四 川 大 学 计 算 机 学 院、软 件 学 院实 验 报 告 课程名称 信息安全产品开发实践 实验课时5实验项目并发服务器II多线程 实验时间2011年10月28号实验目的 1) 继续了解Linux下C语言程序开发的过程2) 了解线程库Pthreads及提供的基本线程的操作线程的属性,了解线程的属性,线程的互斥和同步3) 掌握多线程网络服务器模型4) 能在Linux环境实现TCP多线程并发服务器模型5) 能编写多线程端口扫描程序实验环境 VMware5.0,RedHat Linux 9.0实验内容(算法、程序、步骤和方法) 试验题目1修改远程控制程序服务器程序,将其从循
2、环模式或多进程模式修改为多线程模式试验题目2多线程端口扫描程序实现一个多线程端口扫描程序:要求:1. 能同时扫描5个IP地址;2. 针对每个iP地址,开设100个线程对其进行扫描;3. 如果端口打开,使用函数getservbyport获取其服务名,在屏幕上打印:IP port servername,如果是未知服务,则屏幕显示:ip port unkonown 实验一:先来回顾一下上次实验实现的多进程并发服务器:Unix下的大多数网络服务器程序都是这么编写的,即父进程接受连接,派生子进程,子进程处理与客户的交互。 虽然这种模型很多年来使用得很好,但是fork时有一些问题: (1)fork是昂贵的
3、。内存映像要从父进程拷贝到子进程,所有描述字要在子进程中复制等等。目前有的Unix实现使用一种叫做写时拷贝(copyonwrite)的技术,可避免父进程数据空间向子进程的拷贝。尽管有这种优化技术,fork仍然是昂贵的; (2) fork子进程后,需要用进程间通信(IPC)在父子进程之间传递信息。Fork之前的信息容易传递,因为子进程从一开始就有父进程数据空间及所有描述字的拷贝。但是从子进程返回信息给父进程需要做更多的工作。 ;而上述两个问题可以通过用线程代替进程的方法来克服,接下来我们再来看下进程的一些特点: 线程有助于解决这两个问题。线程有时被称为轻权进程(lightweight proce
4、ss),因为线程比进程“轻权”,一般来说,创建一个线程要比创建一个进程快10100倍。 一个进程中的所有线程共享相同的全局内存,这使得线程很容易共享信息,但是这种简易性也带来了同步问题。 一个进程中的所有线程不仅共享全局变量,而且共享:进程指令、大多数数据、打开的文件(如描述字)、信号处理程序和信号处置、当前工作目录、用户ID和组ID。 但是每个线程有自己的线程ID、寄存器集合(包括程序计数器和栈指针)、栈(用于存放局部变量和返回地址)、error、信号掩码、优先级。 程序的编译gcc o test test.c -lpthread 有了这些理论准备之后我们就可以编程来实现我们的多线程并发服务
5、器了。实验步骤:(1)打开虚拟机,利用VI编辑器打开上次实验的tcpserver.c程序,将其中有进程实现的代码去掉,添加用相关的用线程实现的代码(2)保存tcpserver.c,使用命令gcc o tcpserver tcpserver.c g -lpthread命令编译程序。(3)忽略警告,执行./tcpserver(4) 客户端程序不用修改,直接编译,执行即可(5) 客户端输入命令:ls(6) 打开另外一个终端,再次执行客户端程序:(7)执行命令pwd:(8)第一个客户端输入quit命令,退出(9)第二个客户端输入命令quit,退出(10)通过以上的这几个步骤,说明我们编写的多线程的并发
6、服务器很好的实现了相应的功能,这样我们就完成了第一个实验题目实验二:实验思路;主要分为以下四个部分:(1):从控制端接受用户的输入;(2) :根据用户的输入结果,根据IP地址创建100线程进行扫描1.创建100个线程描述符 pidthread_t * thread; thread = ( pthread_t * )malloc( THREAD_NUM * sizeof(pthread_t) );2.为每个线程创建扫描的分工 for ( int j = 0; j argc - 1; +j ) for ( int i = 0; i THREAD_NUM; +i ) port_segment por
7、t; port.dest = dest_ip j ; port.min_port = i * SEG_LEN + 1; /* the last segment */ if ( i = (THREAD_NUM - 1) ) port.max_port = MAX_PORT; else port.max_port = port.min_port + SEG_LEN - 1; (3):创建线程,开始扫描 if ( pthread_create(&threadi, NULL, scan, (void *)&port) != 0 ) perror( pthread_create failedn ); f
8、ree(thread); exit(-2); (4):释放创建的资源 free(pthread);下图是实现该过程的流程图:根据以上思路我们就可以编程来实现多线程的端口扫描器了(1):打开虚拟机,在Linux下的VI编辑器中编写服务器端程序tcpscanner.c (2)使用命令gcc -o tcpscanner tcpscanner.c -g -lpthread编译; (3):执行命令:./tcpscanner 127.0.0.1 10.0.0.3 10.0.0.234(4)通过观察程序执行的结果,发现程序很好的完成了功能,这样我们也就完成了第二个实验。(接上)实验内容(算法、程序、步骤和方
9、法)附试验源代码:mypopen.c/tcpserver.c#include #include #include #include #include #include #include #include #include #define PORT 8900#define BUFSIZE 2048void * start_routine(void* arg); /声明线程处理函数int execute(char*command,char*buf) FILE *fp; int count; char commandbuf2056; if (NULL=command)|(NULL=buf) perr
10、or(command or buf is emptyn); return -1; count =0; memset(commandbuf,0,2056); strcat(commandbuf,sh -c ); strcat(commandbuf,command); fprintf(stderr,the command is %sn,commandbuf); if (NULL=(fp=popen(commandbuf,r) perror(create pipe errorn); return -1; while (count=(recvnum=read(conn_sock,recvbuf,BUF
11、SIZE) perror(the commucation errorn); close(conn_sock); close(sockfd); return -1; recvbufrecvnum=0; fprintf(stderr,the command is:%sn,recvbuf); if (0=strcmp(recvbuf,quit) fprintf(stderr,the client is quitn); close(conn_sock); break; if (1=(cnt=execute(recvbuf,sendbuf) sprintf(sendbuf,the invalid com
12、mand,please try againn); fprintf(stderr,the result is n%s,sendbuf); if (0=(sendnum=write(conn_sock,sendbuf,strlen(sendbuf) perror(the commucation errorn); close(conn_sock); return -1; close(sockfd);tcpscanner.c#include#include#include#include#include#include#include#include#define SCANLENGTH 655 /每个
13、线程分配655个端口#define THREADNUM 100 /100个线程#define START_PORT 1 /起始端口号#define END_PORT 65535 /结束端口号struct Port /定义端口结构体 int scan_minPort; int scan_maxPort; char *IP; Port;void print_usage(char *str);/打印出错信息void *scan(void * arg);/声明扫描函数int main(int argc, char *argv) int ret; struct sockaddr_in server; s
14、truct servent *serve; if(argc 2) print_usage(argv0); exit(1); /创建100个线程描述符 pthread_t *thread; thread = (pthread_t*) malloc (THREADNUM*sizeof(pthread_t); int j; int i;/为每个线程创建扫描的分工 for(j=1; jargc; +j) for(i=0; iIP = argvj; port-scan_minPort = i*SCANLENGTH+1; if(i = (THREADNUM-1) port-scan_maxPort = E
15、ND_PORT; else port-scan_maxPort = port-scan_minPort+SCANLENGTH-1;/创建线程,开始扫描 if(pthread_create(&threadi,NULL,(void *)scan,(void *)port)!=0) perror(thead_create error!n); free(thread);/ 释放创建的资源 exit(-1); return 0;void print_usage(char *str) printf(the command %s usage is: n,str); printf(%s IP_ADDRESS
16、IP_ADDRESS IP_ADDRESS n,str);/扫描函数的实现void *scan(void * arg) pthread_detach(pthread_self(); int sockfd; int ret; int opt = SO_REUSEADDR; struct sockaddr_in server; struct servent *serve; char *name; struct Port* port = (struct Port*)arg; int start; int end; int scanPort; start = port-scan_minPort; en
17、d = port-scan_maxPort; for(scanPort = start; scanPort!=end; scanPort+) if(-1 = (sockfd = socket(AF_INET,SOCK_STREAM,0) perror(socket failed!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 =
18、 inet_addr(port-IP); server.sin_port = htons(scanPort); ret = connect(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr)+1; if(ret = 0) close(sockfd); continue; else if(ret = 1) if(serve = getservbyport(htons(scanPort),TCP)=NULL) printf(IP=%s scanPort=%d Unknown servicen,port-IP,scanPort); els
19、e printf(IP=%s scanPort=%d s_name=%sn,port-IP,scanPort,serve-s_name); for(name=serve-s_aliases;*name!=NULL;name+) printf(IP=%s scanPort=%d aliase name is %sn,port-IP,scanPort,*name); close(sockfd); 数据记录和计算 详细见上面结 论(结 果) (1)利用多线程技术能实现并发服务器,且比多进程的实现的方式更有效(2)利用多线程技术能加强端口扫描的功能。小 结 通过本实验,我掌握了:1) 进一步熟悉了Li
20、nux下C语言程序开发的过程;2) 了解了一些基本的线程函数3) 掌握了如何利用多线程实现并发服务器4) 会编写多线程端口扫描程序目前我存在的问题有:对线程的函数掌握的不是很熟练指导老师评 议 成绩评定: 指导教师签名:实验报告说明 专业实验中心 实验名称 要用最简练的语言反映实验的内容。如验证某程序、定律、算法,可写成“验证”;分析。实验目的 目的要明确,要抓住重点,可以从理论和实践两个方面考虑。在理论上,验证定理、公式、算法,并使实验者获得深刻和系统的理解,在实践上,掌握使用实验设备的技能技巧和程序的调试方法。一般需说明是验证型实验还是设计型实验,是创新型实验还是综合型实验。实验环境 实验
21、用的软硬件环境(配置)。实验内容(算法、程序、步骤和方法) 这是实验报告极其重要的内容。这部分要写明依据何种原理、定律算法、或操作方法进行实验,要写明经过哪几个步骤。还应该画出流程图(实验装置的结构示意图),再配以相应的文字说明,这样既可以节省许多文字说明,又能使实验报告简明扼要,清楚明白。数据记录和计算 指从实验中测出的数据以及计算结果。结论(结果) 即根据实验过程中所见到的现象和测得的数据,作出结论。小结 对本次实验的体会、思考和建议。备注或说明 可写上实验成功或失败的原因,实验后的心得体会、建议等。 注意: 实验报告将记入实验成绩; 每次实验开始时,交上一次的实验报告,否则将扣除此次实验成绩。