基于线程池实现linux下守护进程运行web目录服务器

LInux先建立线程池,主函数监听套机字,accept后,将连接套接字投入线程池处理。

自己搞的这个线程池,暂时没有发现问题,运行效果还行。

虽然free是线程安全,不可重入的。但是我们并没使用静态变量,所以不会存在问题

下为main函数,运行参数为  ./web  n  k     ;n为想线程池初始化的线程数,k为0为终端运行,k为1则转为守护进程。

运行如图



支持文件的浏览与下载


可能出现在本机上可以访问,在局域网内其他机器不能访问。则解决入下:

service iptables stop  也可以自己配置下iptables的匿名访问

如果想外网能访问,就得配置NAT

#include "unp.h"
#include "threadpoll.h"
#include "work.h"
#include "daemon.h"

int daemon_flag = 0;

int main(int argc, char **argv)
{
	int					listenfd, *connfd, num;
	socklen_t				clilen;
	struct sockaddr_in		cliaddr, servaddr;
	struct in_addr		myaddr;
	const int 				on = 1;
	if( argc != 3){
		exit(0);										/*参数错误*/
	}
	if(atoi(argv[2]) == 1) {
		daemon_ser(argv[0],LOG_USER); 			/*变成守护进程*/
		daemon_flag = 1;
	} else {
		daemon_flag = 0;
	}
	
	if((listenfd = Socket(AF_INET, SOCK_STREAM, 0)) < 0){
		//PST("socket error");
		exit(0);		
	}
	num = atoi(argv[1]);
	bzero(&servaddr, sizeof(servaddr));
	inet_pton(AF_INET, "192.168.0.108", &myaddr);		/*本服务器IP地址*/
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = myaddr.s_addr;
	servaddr.sin_port        = htons(80);						/*web服务为80号端口*/
	setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &on,	sizeof(int));
	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	if(inital_thread_poll(num) != 0) {							/*初始化线程池*/
		exit(0);
	}
	signal(SIGINT,clear_pool);											/*中断时,释放资源*/
	Listen(listenfd, LISTENQ);
	for ( ; ; ) {
		clilen = sizeof(struct sockaddr);
		connfd = (int * )malloc(sizeof(int));					/*每个连接一个字节*/
		if(connfd == NULL) {
			PST("Malloc connfd error");
			exit(0);
		}
		*connfd = accept(listenfd, (SA *) &cliaddr, &clilen);
		if(*connfd < 0) {
			free(connfd);
			continue;
		}
		PST("Add a connect");
		insert_task_2_poll(connfd);				/*增加任务,投入到线程池*/
	}
	clear_pool(SIGINT);									/*退出时释放资源*/
	exit(0);
}




以下为线程池,采用条件和互斥锁同步

#include "unp.h"
#include "threadpoll.h"
#include "work.h"
#include <assert.h>

thread_pool	*pool;	
extern daemon_flag;

/*
*初始化线程池
*/
int inital_thread_poll(int num) {
	pthread_attr_t		attr;
	pthread_t		pid;
	int 				i, err;
	pool = (thread_pool *)malloc(sizeof(thread_pool));	/*在堆上分配*/
	if(pool == NULL) {
		#ifdef PRT
		PST("Malloc error");
		#endif
		return -1;
	}
	assert(pool != NULL);
	pthread_mutex_init( &(pool->mutex), NULL);		/*锁*/
	pthread_cond_init( &(pool->cond), NULL);		/*条件*/
	pool->nthreads = num;			
	pool->totaltasks = pool->runtasks = 0;		/*当前总接受的任务数和运行任务数*/
	pool->shut = 0;														/*关闭标志*/
	pool->head = pool->tail = NULL;
	pool->head = pool->tail = malloc(sizeof(task));		/*初始化头尾指针*/			
	pthread_attr_init( &attr);						/*属性*/
	pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED);
	for( i =0; i < num; i++) {
		if((err = pthread_create( &pid, &attr, thread_func, NULL)) != 0) {	/*创建线程*/
			return err;
		}
	}
	pthread_attr_destroy( &attr);
	return 0;
}
/*
*给线程池中加入任务
*/
void insert_task_2_poll(/*void *(*func)(void *),*/ void *data) { /*添加任务*/
	task *mytask;
	mytask = (task *)malloc(sizeof(task));			/*在堆上分配*/
	if(mytask == NULL) {
		#ifdef PRT
		PST("Malloc task error");
		#endif 
		return;
	}
/*	mytask->func = func;*/
	mytask->data = data;
	pthread_mutex_lock(&(pool->mutex));
	pool->tail->next = mytask;
	mytask->prev = pool->tail;
	pool->tail = mytask;
	pool->tail->next = NULL;
	pool->totaltasks ++;						/*任务数加1*/
	pool->waittasks ++;						/*等待处理的任务数加1*/
	#ifdef PRT
		printf("Add a task ,the total tasks is %d, waittask is %d\n",pool->totaltasks,pool->waittasks);
	#endif
	pthread_cond_signal(&(pool->cond));/*唤醒等待任务的线程*/
	pthread_mutex_unlock(&(pool->mutex));
	return;
}
/*
*删除线程池中尾任务
*/
void del_task_2_poll() {				/*删除任务*/
/*	pthread_mutex_lock(&(pool->mutex));*/
	free(pool->tail->data);
	pool->tail->data = NULL;
	pool->tail = pool->tail->prev;
	free(pool->tail->next);
	pool->tail->next = NULL;
	pool->totaltasks --;
	#ifdef PRT
		printf("Delete a task ,the total tasks is %d, waittask is %d\n",pool->totaltasks,pool->waittasks);
	#endif
/*	pthread_mutex_lock(&(pool->mutex));*/
}
/*
*线程函数
*/
void *thread_func(void *arg) {  			/*等待任务,无则阻塞*/
	/*void 	*(*functemp)(void *);*/
	int		connfd;
	for( ; ;) {
		pthread_mutex_lock(&(pool->mutex));
		while(pool->waittasks == 0) 
			pthread_cond_wait(&(pool->cond), &(pool->mutex));
	/*	functemp = pool->tail->func;*/
		connfd = *((int *)(pool->tail->data));
		pool->runtasks ++;					/*处理过的任务数*/
		pool->waittasks --;					/*等待处理的任务数*/
		del_task_2_poll();						/*释放这个任务*/
		pthread_mutex_unlock(&(pool->mutex));	/*解锁,使其他线程可以等待其他任务*/
		serve_machine(&connfd);				/*任务开始执行*/
	}
}
/*
*释放线程池资源
*/
void clear_pool(int	signo) {				/*清除线程池*/
	task 	*temp;
	#ifdef PRT
	printf("\n服务器正在关闭...\n");
	#endif
	pthread_mutex_lock(&(pool->mutex));
	temp = pool->head->next;
	for(; temp != NULL; temp = pool->head->next) {
		free(pool->head->data);
		pool->head->data = NULL;
		if(pool->head->prev != NULL){
			free(pool->head->prev);
			pool->head->prev = NULL;
		}
		free(pool->head);
		pool->head = NULL;
		pool->head = temp;
	}
	/*free(temp);*/
	pthread_mutex_unlock(&(pool->mutex));
	pthread_mutex_destroy(&(pool->mutex));
	pthread_cond_destroy(&(pool->cond));
	free(pool);
	pool = NULL;
	exit(0);
}




线程池 头文件

#ifndef _THREAD_
#define _THREAD_
#include "unp.h"
typedef struct demytask {							/*任务*/
	//void 				*(*func)(void *arg);			/*套接字处理函数指针*/
	void					*data;						/*连接套接字*/
	struct demytask		*next;						/*后向索引*/
	struct demytask		*prev;						/*后向索引*/
}task;
typedef struct pool {
	pthread_mutex_t 	mutex;				/*锁和条件*/
	pthread_cond_t	cond;
	int				nthreads;			/*线程池中线程数*/
	int				totaltasks;			/*线程池中总的任务数*/
	int				runtasks;			/*正在服务的任务数*/
	int				shut;				/*线程池关闭状态*/
	int				waittasks;			/*等待空闲线程的任务数*/
	task				*head;				/*任务头指针*/
	task				*tail;				/*任务尾指针*/
	/*pthread_t	*threads*/				/*线程ID数组,暂无用*/
}thread_pool;

void *thread_func(void *arg);			/*线程函数*/
int inital_thread_poll(int num);		/*线程池初始化*/
void insert_task_2_poll(/*void *(*func)(void *),*/ void *data);/*增加任务*/
void del_task_2_poll();				/*删除任务*/
void clear_pool(int	signo) ;			/*线程池资源释放*/
#endif


遍历目录,并响应请求,对于html语法不熟悉,参考网络

#include "work.h"
#include <dirent.h>

char  *rootdir = "/";		/*初始页*/
char *port = "80";
char *host = "192.168.0.108";

char *dir_up(char *dirpath)
{

    static char path[MAXLINE];
    char *end;
    int len;
    strcpy(path, dirpath);
    len = strlen(path);
    if(strcmp(dirpath, "/") == 0)
			return path;
    if(len > 1) {
    	while((path[len-1] == '/')) {
    		path[len-1] = '\0';
    		len --;
    	}
    	end = (strrchr(path, '/'));
    	*end = '\0';
    }
    if(path - end == 0) {
    	path[0] = '/';
    	path[1] = '\0';
    	return path;
    }
 		return path;
}
void serve_machine(int *connfd) {
		char 	buf[MAXLINE], query[MAXLINE+1];
		int		n;
		n = recv(*connfd, buf, sizeof(buf), 0);		/*读取客户端指令*/
		sscanf(buf, "GET %s HTTP", query);
		if(n <= 0) {
			close(*connfd);
			return;
		}
		FILE *file;
		file =fdopen(*connfd, "w");
		send_2_server(file, query);
		close(*connfd);
}

void send_2_server(FILE * client_sock, char *path)
{
    struct dirent *dirent;
    struct stat info;
    char filename[MAXLINE];
    DIR *dir;
    int fd, len, ret;
    int space = 1024, nread = 0;
    char *p, *realpath, *realfilename, *nport;
    len = strlen(rootdir) + strlen(path) + 1;
    realpath = malloc(len + 1);
    bzero(realpath, len + 1);
    sprintf(realpath, "%s/%s", rootdir, path);
    len = strlen(port) + 1;
    nport = malloc(len + 1);
    bzero(nport, len + 1);
    sprintf(nport, ":%s", port);
    if (stat(realpath, &info)) {
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer: DAS by renzhenwen\r\nConnection: close\r\n\r\n<html><head><title>%d - %s</title></head>"
                "<body><font size=+4>基于Linux线程池的目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">", errno,strerror(errno));
        fprintf(client_sock,
                "</table><font color=\"CC0000\" size=+2>不能获取当前信息:\n%s %s</font></body></html>",path, strerror(errno));
        goto out;
    }
    if (S_ISREG(info.st_mode)) {
        fd = open(realpath, O_RDONLY);
        len = lseek(fd, 0, SEEK_END);
				nread = 0;
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer: DAS by renzhenwen\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n",len);
				p = (char *) malloc(space + 1);
        while( len > 0 ) {  		/*单缓冲读取文件*/
        	bzero(p, space + 1);
        	lseek(fd, nread, SEEK_SET);
        	ret = read(fd, p, space);
        	fwrite(p, ret, 1, client_sock);
        	len -= ret;
        	nread += ret; 
      }
      free(p);
      close(fd);
    } else if (S_ISDIR(info.st_mode)) {
        dir = opendir(realpath);
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer: DAS by renzhenwen\r\nConnection: close\r\n\r\n<html><head><title>%s</title></head>"
                "<body><font size=+4>基于Linux线程池的目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">", path);
        fprintf(client_sock,
                "<caption><font size=+3>目录 %s</font></caption>\n",path);
        fprintf(client_sock,
                "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n");
        if (dir == 0) {
            fprintf(client_sock,
                    "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",strerror(errno));
            return;
        }
        while ((dirent = readdir(dir)) != 0) {
            if (strcmp(path, "/") == 0)
                sprintf(filename, "/%s", dirent->d_name);
            else
                sprintf(filename, "%s/%s", path, dirent->d_name);
            fprintf(client_sock, "<tr>");
            len = strlen(rootdir) + strlen(filename) + 1;
            realfilename = malloc(len + 1);
            bzero(realfilename, len + 1);
            sprintf(realfilename, "%s/%s", rootdir, filename);
            if (stat(realfilename, &info) == 0) {
                if (strcmp(dirent->d_name, "..") == 0)
                    fprintf(client_sock,
                            "<td><a href=\"http://%s%s%s\">(parent)</a></td>",
                            host, atoi(port) == 80 ? "" : nport,
                            dir_up(path));
                else
                    fprintf(client_sock,
                            "<td><a href=\"http://%s%s%s\">%s</a></td>",
                            host, atoi(port) == 80 ? "" : nport, filename,dirent->d_name);
                if (S_ISDIR(info.st_mode))
                    fprintf(client_sock, "<td>目录</td>");
                else if (S_ISREG(info.st_mode))
                    fprintf(client_sock, "<td>%d</td>", info.st_size);
                else if (S_ISLNK(info.st_mode))
                    fprintf(client_sock, "<td>链接</td>");
                else if (S_ISCHR(info.st_mode))
                    fprintf(client_sock, "<td>字符设备</td>");
                else if (S_ISBLK(info.st_mode))
                    fprintf(client_sock, "<td>块设备</td>");
                else if (S_ISFIFO(info.st_mode))
                    fprintf(client_sock, "<td>FIFO</td>");
                else if (S_ISSOCK(info.st_mode))
                    fprintf(client_sock, "<td>Socket</td>");
                else
                    fprintf(client_sock, "<td>(未知)</td>");
                fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));
            }
            fprintf(client_sock, "</tr>\n");
            free(realfilename);
        }
        fprintf(client_sock, "</table></center></body></html>");
    } else {
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer: DAS by renzhenwen\r\nConnection: close\r\n\r\n<html><head><title>permission denied</title></head>"
                "<body><font size=+4>基于Linux线程池的目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">");
        fprintf(client_sock,
                "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html>",path);
    }
  out:
    free(realpath);
    free(nport);
}

头文件

#ifndef  _WORK_
#define  _WORK_
#include "unp.h"

void serve_machine(int *connfd) ;		/*为客户端服务函数*/
void  send_2_server(FILE * client_sock, char *Path);
#endif

普通进程编程守护进程

#include "daemon.h"
#include "unp.h"
/*
* 普通进程变成守护进程,APUE很详细哦
*/
int  daemon_ser(const char *name,int facility) {
	int 		i;
	pid_t		pid;
	if(( pid = fork( )) < 0) {
		return -1;
	} else if (pid > 0) {
		_exit(0);
	}
	
	if(setsid( ) < 0) {
		return -1;
	}
	signal(SIGHUP, SIG_IGN);
	if(( pid = fork( )) < 0) {
		return -1;
	} else if (pid > 0) {
		_exit(0);
	}
	chdir("/");
	for(i = 0; i < MAXFD; i++ ) {
		close(i);
	}
	open("/dev/null", O_RDONLY);
	open("/dev/null", O_RDWR);
	open("/dev/null", O_RDWR);
	openlog(name, LOG_PID, facility);
	return 0;
}

/*
* 自定义输出函数,可以递交给syslog守护进程或者终端
*/
void PST(char *ptr) {
	syslog(LOG_INFO | LOG_LOCAL7,ptr);
}

头文件

#ifndef _DAEMON_
#define _DAEMON_
#include <syslog.h>
#include <string.h>


#define MAXFD		64
extern int daemon_flag;
int  daemon_ser(const char *name,int facility);
void PST(char *ptr);

#endif


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值