Boa是一款轻量级WebServer,向用户提供基于http协议的服务。
Boa接收和响应客户请求的流程
Boa作为一款http服务器,其最终要的功能就是接收和响应客户请求。
一般而言服务器程序都有相似的编程模型,所有服务器程序都必须完成下面的几件事情:
- 创建监听端口。监听端口相当于应用的门户,所有客户端都必须通过监听端口接入进来。
- 使用
accept
系统调用接入客户端。 在该步骤客户端就与服务器建立了一条可以用于全双工通信的管道(或称连接)。 - 使用
read
和write
系统调用,从客户端接收数据或向客户端发送数据。
下面我们来看下Boa具体是怎么完成上述三件事情的。
创建监听套接字
在进入main函数不久,我们就可以看到一条函数调用 server_s = create_server_socket();
。
在这个函数里创建了套接字,并将其绑定了Boa的服务端口,然后通过 listen
完成了监听套接字的创建。
static int create_server_socket(void)
{
int server_s;
server_s = socket(SERVER_PF, SOCK_STREAM, IPPROTO_TCP);
if (server_s == -1) {
DIE("unable to create socket");
}
/* server socket is nonblocking */
if (set_nonblock_fd(server_s) == -1) {
DIE("fcntl: unable to set server socket to nonblocking");
}
/* close server socket on exec so CGIs can't write to it */
if (fcntl(server_s, F_SETFD, 1) == -1) {
DIE("can't set close-on-exec on server socket!");
}
/* reuse socket addr */
if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
sizeof (sock_opt))) == -1) {
DIE("setsockopt");
}
/* Internet family-specific code encapsulated in bind_server() */
if (bind_server(server_s, server_ip, server_port) == -1) {
DIE("unable to bind");
}
/* listen: large number just in case your kernel is nicely tweaked */
if (listen(server_s, backlog) == -1) {
DIE("unable to listen");
}
return server_s;
}
接入客户端连接
创建完监听套接字之后,在main函数中调用了 loop
。这时就正式进入了Boa的主循环了。
Boa的主循环总的来说就是不停的接入客户端连接,
数据结构
每一个请求的接入以及数据交互是由一个 request
结构管理的
struct request { /* pending requests */
...
int data_fd; /* fd of data */
int post_data_fd; /* fd for post data tmpfile */
int fd; /* client's socket fd */
...
struct request *next; /* next */
struct request *prev; /* previous */
};
«Previous: C语言中使用二维数组的另一种方式
»Next: shell编程基础