3.8.2 清理文件句柄
Nginx会异步地将整个文件高效地发送给用户,但是我们必须要求HTTP框架在响应发送完毕后关闭已经打开的文件句柄,否则将会出现句柄泄露问题。设置清理文件句柄也很简单,只需要定义一个ngx_pool_cleanup_t结构体(这是最简单的方法,HTTP框架还提供了其他方式,在请求结束时回调各个HTTP模块的cleanup方法,将在第11章介绍),将我们刚得到的文件句柄等信息赋给它,并将Nginx提供的ngx_pool_cleanup_file函数设置到它的handler回调方法中即可。首先介绍一下ngx_pool_cleanup_t结构体。
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
struct ngx_pool_cleanup_s{
//执行实际清理资源工作的回调方法
ngx_pool_cleanup_pt handler;
//handler回调方法需要的参数
void*data;
//下一个ngx_pool_cleanup_t清理对象,如果没有,需置为NULL
ngx_pool_cleanup_t*next;
};
设置好handler和data成员就有可能要求HTTP框架在请求结束前传入data成员回调handler方法。接着,介绍一下专用于关闭文件句柄的ngx_pool_cleanup_file方法。
void ngx_pool_cleanup_file(void*data)
{
ngx_pool_cleanup_file_t*c=data;
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC,c->log,0,"file cleanup:fd:%d",c->fd);
if(ngx_close_file(c->fd)==NGX_FILE_ERROR){
ngx_log_error(NGX_LOG_ALERT,c->log,ngx_errno,
ngx_close_file_n"\"%s\"failed",c->name);
}
}
ngx_pool_cleanup_file的作用是把文件句柄关闭。从上面的实现中可以看出,ngx_pool_cleanup_file方法需要一个ngx_pool_cleanup_file_t类型的参数,那么,如何提供这个参数呢?在ngx_pool_cleanup_t结构体的data成员上赋值即可。下面介绍一下ngx_pool_cleanup_file_t的结构。
typedef struct{
//文件句柄
ngx_fd_t fd;
//文件名称
u_char*name;
//日志对象
ngx_log_t*log;
}ngx_pool_cleanup_file_t;
可以看到,ngx_pool_cleanup_file_t中的对象在ngx_buf_t缓冲区的file结构体中都出现过了,意义也是相同的。对于file结构体,我们在内存池中已经为它分配过内存,只有在请求结束时才会释放,因此,这里简单地引用file里的成员即可。清理文件句柄的完整代码如下。
ngx_pool_cleanup_t*cln=ngx_pool_cleanup_add(r->pool,sizeof(ngx_pool_cleanup_file_t));
if(cln==NULL){
return NGX_ERROR;
}
cln->handler=ngx_pool_cleanup_file;
ngx_pool_cleanup_file_t*clnf=cln->data;
clnf->fd=b->file->fd;
clnf->name=b->file->name.data;
clnf->log=r->pool->log;
ngx_pool_cleanup_add用于告诉HTTP框架,在请求结束时调用cln的handler方法清理资源。
至此,HTTP模块已经可以向客户端发送文件了。下面介绍一下如何支持多线程下载与断点续传。