`
bachmozart
  • 浏览: 111343 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

lighttpd 学习笔记一

阅读更多
从server.c的main函数看起,启动流程大体如下:

server_init 函数初始化lighttpd 的server 数据结构,涉及到其中一些buffer,array的结构初始化工作,主要参考的数据结构buffer,array,chunkqueue等等

通过启动参数-f 读取配置文件 config_read

if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
		/* we are setuid-root */

		log_error_write(srv, __FILE__, __LINE__, "s",
				"Are you nuts ? Don't apply a SUID bit to this binary");

		server_free(srv);
		return -1;
}

这段代码是当lighttpd binary 被setuid(类似 chmod 4755)时,禁止运行,不明白为什么要这样处理,回头再了解一下
i_am_root 是 getuid==0的结果,即root用户 getuid会返回 0,非root会返回正整数

后面比较奇怪的地方时
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
		/* select limits itself
		 *
		 * as it is a hard limit and will lead to a segfault we add some safety
		 * */
		srv->max_fds = FD_SETSIZE - 200;
	} else {
		srv->max_fds = 4096;
	}

默认没有修改配置文件的情况下,linux 2.6的srv->event_handler应该是epoll,就是执行else分支,我用gdb也是这个结果,为什么max_fds最多只有4096呢?libevent里直接就是rlimit里的 rlim_cur,通常会被设置成65535

接下来比较重要的是  network_init 调用(参考network.c文件)

在network_init中也就是调用 socket,setsocketopt,bind,listen等操作,创建出一个listen socket

#ifdef HAVE_FORK
	/* start watcher and workers */
	num_childs = srv->srvconf.max_worker;
	if (num_childs > 0) {
		int child = 0;
		while (!child && !srv_shutdown && !graceful_shutdown) {
			if (num_childs > 0) {
				switch (fork()) {
				case -1:
					return -1;
				case 0:
					child = 1;
					break;
				default:
					num_childs--;
					break;
				}
			} else {
				int status;

				if (-1 != wait(&status)) {
					/** 
					 * one of our workers went away 
					 */
					num_childs++;
				} else {
					switch (errno) {
					case EINTR:
						/**
						 * if we receive a SIGHUP we have to close our logs ourself as we don't 
						 * have the mainloop who can help us here
						 */
						if (handle_sig_hup) {
							handle_sig_hup = 0;

							log_error_cycle(srv);

							/**
							 * forward to all procs in the process-group
							 * 
							 * we also send it ourself
							 */
							if (!forwarded_sig_hup) {
								forwarded_sig_hup = 1;
								kill(0, SIGHUP);
							}
						}
						break;
					default:
						break;
					}
				}
			}
		}

		/**
		 * for the parent this is the exit-point 
		 */
		if (!child) {
			/** 
			 * kill all children too 
			 */
			if (graceful_shutdown) {
				kill(0, SIGINT);
			} else if (srv_shutdown) {
				kill(0, SIGTERM);
			}

			log_error_close(srv);
			network_close(srv);
			connections_free(srv);
			plugins_free(srv);
			server_free(srv);
			return 0;
		}
	}
#endif


这段代码的功能是fork出若干child进程,然后父进程投入睡眠等待子进程退出,如果有退出的子进程,父进程会马上在fork出新的子进程,就是所谓的 watcher - worker的模型,这个网上的资料也有很清楚的论述

接下来子进程(可能很多个)开始注册事件
lighttpd也是使用event-driven模型,fdevents是全局的事件处理器数据结构,实现的功能类似于libevent

if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
		log_error_write(srv, __FILE__, __LINE__,
				"s", "fdevent_init failed");
		return -1;
	}

fdevent_init初始化事件处理器
具体的事件选择应该已经通过读取配置文件设置好了,以epoll为例子,实际执行的是
ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
#define SET(x) \
	ev->x = fdevent_linux_sysepoll_##x;

	SET(free);
	SET(poll);

	SET(event_del);
	SET(event_add);

	SET(event_next_fdndx);
	SET(event_get_fd);
	SET(event_get_revent);

	if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
		fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
			__FILE__, __LINE__, strerror(errno));

		return -1;
	}

	if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) {
		fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
			__FILE__, __LINE__, strerror(errno));

		close(ev->epoll_fd);

		return -1;
	}

	ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));



#define SET(x) \
ev->x = fdevent_linux_sysepoll_##x;

##的作用是字符连接即初始化函数指针
ev->free=fdevent_linux_sysepoll_free等操作

通过上面代码初始化好了事件处理器srv->ev

接下来调用 network_register_fdevents (文件network.c)

int network_register_fdevents(server *srv) {
	size_t i;

	if (-1 == fdevent_reset(srv->ev)) {
		return -1;
	}

	/* register fdevents after reset */
	for (i = 0; i < srv->srv_sockets.used; i++) {
		server_socket *srv_socket = srv->srv_sockets.ptr[i];

		fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
		fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
	}
	return 0;
}


此时srv->srv_sockets.used应该为1,就是刚刚建立的listen fd

fdevent_register代码
int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
	fdnode *fdn;

	fdn = fdnode_init();
	fdn->handler = handler;
	fdn->fd      = fd;
	fdn->ctx     = ctx;

	ev->fdarray[fd] = fdn;

	return 0;
}

fdarray用于保存fd与对应回调handler及参数ctx之间的关系,将来能以O(1)的性能查找到某个fd对应的回调函数及参数

server.c最后就是一个巨大的循环

/* main-loop */
	while (!srv_shutdown) {
		//巨大的循环代码段
	}

	if (srv->srvconf.pid_file->used &&
	    srv->srvconf.changeroot->used == 0 &&
	    0 == graceful_shutdown) {
		if (0 != unlink(srv->srvconf.pid_file->ptr)) {
			if (errno != EACCES && errno != EPERM) {
				log_error_write(srv, __FILE__, __LINE__, "sbds",
						"unlink failed for:",
						srv->srvconf.pid_file,
						errno,
						strerror(errno));
			}
		}
	}

#ifdef HAVE_SIGACTION
	log_error_write(srv, __FILE__, __LINE__, "sdsd", 
			"server stopped by UID =",
			last_sigterm_info.si_uid,
			"PID =",
			last_sigterm_info.si_pid);
#else
	log_error_write(srv, __FILE__, __LINE__, "s", 
			"server stopped");
#endif

	/* clean-up */
	log_error_close(srv);
	network_close(srv);
	connections_free(srv);
	plugins_free(srv);
	server_free(srv);

	return 0;




由于fork会原样复制父进程的heap和stack区,并保持独立,所以fork方式的好处就是完全不需要共享任何东西,代价是内存占用量要比较多






分享到:
评论

相关推荐

    php入门到精通学习笔记

    【PHP入门到精通学习笔记】 PHP(Personal Home Page)是一种广泛使用的开源脚本语言,尤其在Web开发领域中。PHP最初是由Rasmus Lerdorf创建的,后来由Zend公司负责维护和商业化。PHP的设计目标是使得编写过程更...

    WEB学习笔记资源整合,看完这个你的web就能更上一层楼

    【Web学习笔记资源整合】 在深入理解Web开发的过程中,首先我们需要了解两种主要的软件体系结构:C/S(客户端/服务器)模式和B/S(浏览器/服务器)模式。 1. C/S模式(事件驱动) C/S架构是一种传统的应用模型,...

    Nginx-笔记1

    【虚拟主机配置】是Nginx的一个重要功能,它允许在一个物理服务器上托管多个独立的网站,每个网站对应不同的域名或IP。通过配置server块,我们可以设定不同站点的根目录、访问控制和重定向规则。 【Location匹配...

    韩顺平php笔记

    除了Apache,还有如Lighttpd(轻量级Web服务器,适合高并发场景)和Nginx(Engine X,俄罗斯开发,也擅长处理高并发)等,它们各有优势,可根据具体需求选择。 总的来说,PHP作为一种动态网页技术,因其开源、跨...

    韩顺平PHP笔记

    常见的Web服务器包括IIS、Lighttpd和Apache。Apache是开源且广泛应用的Web服务器,可以作为操作系统服务运行。通过命令行或服务管理工具可以启动、关闭或重启Apache。例如,使用`httpd -k start`、`httpd -k ...

    PHP 韩顺平课程笔记

    韩顺平的PHP教学课程旨在帮助学习者掌握这一技能,配合视频教程,使学习过程更加高效。 【动态网页技术的发展历程】 1. CGI(Common Gateway Interface,通用网关接口):早期的动态网页技术,用于连接Web服务器和...

    NetRotuer之像学单片机一样学linux笔记1.1演示系统归纳.pdf

    《NetRouter之像学单片机一样学Linux笔记1.1》主要介绍了如何以类似学习单片机的方式去掌握嵌入式Linux系统,特别强调了实际操作和实践的重要性。以下是笔记中的关键知识点: 1. **核心板基础系统演示**: - 核心...

    EaglePHP_jb51

    1. **jb51.net.txt**:这个文件可能包含了jb51.net网站上关于EaglePHP的教程、文档或者一些重要的笔记。jb51.net是一个知名的中文技术网站,提供了大量的编程教程和资源,因此这个文本文件很可能包含EaglePHP的使用...

    moin-1.9.3

    1. **增强的用户体验**:moin-1.9.3版本提升了用户界面的友好性,使得浏览和编辑Wiki页面更为流畅。同时,改进的搜索功能使得查找信息更加高效。 2. **版本控制**:moinmoin提供了完善的版本控制机制,每个页面的每...

    高性能高并发服务器架构大全

    1、一台服务器 71 2、两台服务器 72 3、四台服务器 73 4、五台服务器 73 5、更多服务器 74 6、现在我们在哪里: 75 7、现在我们在哪里 78 8、现在我们在哪里 79 9、缓存 80 10、Web访问负载均衡 80 11、...

Global site tag (gtag.js) - Google Analytics