Nginx模块开发(2)————下载文件
Nginx的HTTP模块下载文件和传送缓冲区的字符串差不多,只需将文件标志置为1即可,我转送的文件是mp3的,所以HTTP的那个mine 类型要写为audio/mp3,二话不说了,贴代码,代码和之前那个helloworld差不多。
//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief:nginx的HTTP模块:发送文件
#include <ngx_config.h>//包含必要的头文件
#include <ngx_core.h>
#include <ngx_http.h>
//先声明函数
static char *ngx_http_lcwsendfile(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_lcwsendfile_handler(ngx_http_request_t *r);
//ngx_command_t定义模块的配置文件参数
static ngx_command_t ngx_http_lcwsendfile_commands[] =
{
    {
     //配置项名称,就是配置文件里面的那个名称
        ngx_string("lcwsendfile"),
        //配置项类型,将指定配置项可以出现的位置
        //例如出现在server{}或location{}中,以及他可以携带的参数个数
         NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
         //ngx_command_t结构体中的set成员,
         //当在某个配置块中出现lcwsendfile配置项时,Nginx将会调用ngx_http_lcwsendfile方法
         //ngx_http_lcwsendfile方法将在下面实现
         ngx_http_lcwsendfile,
         //在配置文件中的偏移量conf
         NGX_HTTP_LOC_CONF_OFFSET,
         //offset通常用于使用预设的解析方法解析配置项,需要与conf配合使用
         0,
         //配置项读取后的处理方法,必须是ngx_conf_post_t结构的指针
         NULL
    },
    //ngx_null_command是一个空的ngx_command_t结构,用来表示数组的结尾
    ngx_null_command
};
//ngx_http_module_t的8个回调方法,因为目前没有什么工作是必须在HTTP框架初始化
//时完成的,所以暂时不必实现ngx_http_module_t的8个回调方法
static ngx_http_module_t ngx_http_lcwsendfile_module_ctx =
{
    NULL, // preconfiguration解析配置文件前调用
    NULL, // postconfiguration 完成配置文件解析后调用
    NULL, // create main configuration当需要创建数据结构用于存储main级别的
                //(直属于http{}块的配置项)的全局配置项时
    NULL, // init main configuration常用于初始化main级别的配置项
    NULL, // create server configuration当需要创建数据结构用于存储srv级别的
                //(直属于server{}块的配置项)的配置项时
    NULL, // merge server configuration用于合并main级别和srv级别下的同名配置项
    NULL, // create location configuration 当需要创建数据结构用于存储loc级别的
                //(直属于location{}块的配置项)的配置项时
    NULL // merge location configuration 用于合并srv和loc级别下的同名配置项
};
//定义lcwsendfile模块
//lcwtest模块在编译时会被加入到ngx_modules全局数组中
//Nginx在启动时,会调用所有模块的初始化回调方法
//HTTP框架初始化时会调用ngx_http_module_t中的8个方法
//HTTP模块数据结构
ngx_module_t ngx_http_lcwsendfile_module =
{
    NGX_MODULE_V1,//该宏为下面的ctx_index,index,spare0,spare1,spare2,spare3,version变量
                 //提供了初始化的值:0,0,0,0,0,0,1
    //ctx_index表示当前模块在这类模块中的序号
    //index表示当前模块在所有模块中的序号,Nginx启动时会根据ngx_modules数组设置各模块的index值
    //spare0 spare系列的保留变量,暂未使用
    //spare1
    //spare2
    //spare3
    //version模块的版本,便于将来的扩展,目前只有一种,默认为1
    &ngx_http_lcwsendfile_module_ctx, //ctx用于指向一类模块的上下文结构
    ngx_http_lcwsendfile_commands, //commands将处理nginx.conf中的配置项
    NGX_HTTP_MODULE, //模块的类型,与ctx指针紧密相关,取值范围是以下5种:
                            //NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,NGX_EVENT_MODULE,NGX_MAIL_MODULE
    //以下7个函数指针表示有7个执行点会分别调用这7种方法,对于任一个方法而言,如果不需要nginx在某个是可执行它
    //那么简单地将他设为空指针即可
    NULL, //master进程启动时回调init_master
    NULL, //init_module回调方法在初始化所有模块时被调用,在master/worker模式下,
                                    //这个阶段将在启动worker子进程前完成
    NULL, //init_process回调方法在正常服务前被调用,在master/worker模式下,
                                    //多个worker子进程已经产生,在每个worker子进程的初始化过程会调用所有模块的init_process函数
    NULL, //由于nginx暂不支持多线程模式,所以init thread在框架代码中没有被调用过
    NULL, // exit thread,也不支持
    NULL, //exit process回调方法将在服务停止前调用,在master/worker模式下,worker进程会在退出前调用它
    NULL, //exit master回调方法将在master进程退出前被调用
    NGX_MODULE_V1_PADDING //这里是8个spare_hook变量,是保留字段,目前没有使用,Nginx提供了NGX_MODULE_V1_PADDING宏来填充
};
/******************************************************
函数名:ngx_http_lcwsendfile(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
参数:
功能:lcwsendfile方法的实现
*******************************************************/
static char* ngx_http_lcwsendfile(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t *clcf;
    //首先找到lcwtest配置项所属的配置块,clcf貌似是location块内的数据
    //结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说在每个
    //http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    //http框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果
    //请求的主机域名、URI与lcwsendfile配置项所在的配置块相匹配,就将调用我们
    //实现的ngx_http_lcwsendfile_handler方法处理这个请求
    //ngx_http_lcwsendfile_handler将在下面实现
    clcf->handler = ngx_http_lcwsendfile_handler;
    return NGX_CONF_OK;
}
/******************************************************
函数名:ngx_http_lcwsendfile_handler(ngx_http_request_t *r)
参数:ngx_http_request_t结构体
功能:ngx_http_lcwtest_handler方法的实现
*******************************************************/
static ngx_int_t ngx_http_lcwsendfile_handler(ngx_http_request_t *r)
{
    //必须是GET或者HEAD方法,否则返回405 Not Allowed
    if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
    {
        return NGX_HTTP_NOT_ALLOWED;
    }
    //丢弃请求中的包体
    ngx_int_t rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK)
    {
        return rc;
    }
    //构造ngx_buf_t结构准备发送包体
    ngx_buf_t *b;
    //开辟ngx_buf_t缓冲区
    b = ngx_palloc(r->pool, sizeof(ngx_buf_t));
    //要打开的文件
    u_char* filename = (u_char*)"/mnt/hgfs/lcw_program/张杰 - My Sunshine.mp3";
    b->in_file = 1;//将in_file设置为1就表示ngx_buf_t缓冲区传送的是文件而不是内存
    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    //打开文件传送文件描述符
    b->file->fd = ngx_open_file(filename, NGX_FILE_RDONLY | NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0);
    b->file->log = r->connection->log;
    b->file->name.data = filename;
    b->file->name.len = sizeof(filename) - 1;
    if (b->file->fd <= 0)//打开失败
    {
        return NGX_HTTP_NOT_FOUND;
    }
    //支持断点续传
    r->allow_ranges = 1;
    //获取文件长度ngx_file_info是linux系统中stat的一个宏
    if (ngx_file_info(filename, &b->file->info) == NGX_FILE_ERROR)
    {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    //设置缓冲区指向的文件块,这里是告诉Nginx从文件的file_pos偏移量开始发送文件
    //一直到达file_last偏移处截止
    b->file_pos = 0;
    b->file_last = b->file->info.st_size;
    //接下来要关闭文件句柄,否则会出现句柄泄露问题,于是定义如下结构体
    //ngx_pool_cleanup_add用于告诉HTTP框架,在请求结束时调用cln的handler方法清理资源
    ngx_pool_cleanup_t* cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
    if (cln == NULL)
    {
        return NGX_ERROR;
    }
    //赋值执行实际清理资源工作的回调方法,ngx_pool_cleanup_file方法的作用是把文件句柄关闭
    //ngx_pool_cleanup_file方法需要一个ngx_pool_cleanup_file_t类型的参数
    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_file_t参数传给ngx_pool_cleanup_file方法?
    //设置返回的Content-Type。注意,ngx_str_t有一个很方便的初始化宏
    //ngx_string,它可以把ngx_str_t的data和len成员都设置好
    ngx_str_t type = ngx_string("audio/mp3");
    //设置返回状态码
    r->headers_out.status = NGX_HTTP_OK;
    //响应包是有包体内容的,所以需要设置Content-Length长度
    r->headers_out.content_length_n = b->file->info.st_size;
    //设置Content-Type
    r->headers_out.content_type = type;
    //发送http头部
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
    {
        return rc;
    }
    //构造发送时的ngx_chain_t结构体
    ngx_chain_t out;
    //赋值ngx_buf_t
    out.buf = b;
    //设置next为NULL
    out.next = NULL;
    //最后一步发送包体,http框架会调用ngx_http_finalize_request方法
    //结束请求
    return ngx_http_output_filter(r, &out);
}配置文件也是差不多,编译方法也一样。不过我总是遇到一个问题,就是在windows新建的config文件有时候好像被识别不了,最后我在linux下写这个文件就可以了有点奇怪 
还有编译之后把模块加进nginx里,然后好像上次的那个就没有了,难道以后都得全部加进去吗? 
运行可以得到下面的结果: 
 
下载成功, 
 
是张杰的MySunshine,文件没有损坏,可以听
Nginx模块开发(2)————下载文件的更多相关文章
- 【转】Nginx模块开发入门
		转自: http://kb.cnblogs.com/page/98352/ 结论:对Nginx模块开发入门做了一个helloworld的示例,简单易懂.也有一定的深度.值得一看. Nginx模块开发入 ... 
- Nginx模块开发入门
		前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ... 
- [转] Nginx模块开发入门
		前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ... 
- Nginx模块开发入门(转)
		前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ... 
- Nginx模块开发入门(转)
		前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ... 
- FW:  Nginx模块开发入门
		前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ... 
- 解剖Nginx·模块开发篇(1)跑起你的 Hello World 模块!
		1 学习 Nginx 模块开发需要有哪些准备? 需要的预备知识不多,有如下几点: 有过一些 C 语言的编程经历: 知道 Nginx 是干嘛的,并有过编写或改写 Nginx 的配置文件的经历. OK,就 ... 
- linux下nginx模块开发入门
		本文模块编写参考http://blog.codinglabs.org/articles/intro-of-nginx-module-development.html 之前讲了nginx的安装,算是对n ... 
- 用 requests 模块从 Web 下载文件
		用 requests 模块从 Web 下载文件 requests 模块让你很容易从 Web 下载文件,不必担心一些复杂的问题,诸如网络错误.连接问题和数据压缩.requests 模块不是 Python ... 
- nginx 访问localhost老是下载文件不能打开网页什么情况?
		nginx打开网页直接下载文件的问题 nginx sites-available文件里的default已经修改过root 路径了. 但是访问localhost的时候总是直接下载网页而不是打开网址 很奇 ... 
随机推荐
- C++语言实现顺序栈
			C++语言实现顺序栈 在写C语言实现顺序栈的时候,我已经向大家介绍了栈的特点以及介绍了栈的相关操作,并利用C语言实现了相关算法.在这里小编就不在继续给大家介绍了,需要温习的可以去我的博客看看.在这篇博 ... 
- 06-移动web之flex布局
			一.基本概念 flex布局又叫伸缩布局 .弹性布局 .伸缩盒布局 .弹性盒布局 Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. ... 
- vuepress+gitee 构建在线项目文档
			目录 快速入门 在现有vue项目中安装本地开发依赖vuepress 在现有vue项目根目录下创建docs目录 创建并配置文档首页内容 运行,查看效果 可能会出现vue和vue-server-rende ... 
- Extjs更新grid
			基于Extjs4.2 原理是创建一个新的store,来覆盖原有的store. //创建数据 var newdatas = { name: "ly", age: 17, adress ... 
- HttpWebRequest在Post的时候,遇到特殊符号+号(加号)变成空格了
			今天在调用一个外部接口的时候遇到一个问题,外部接口说要用FOMR的POST方法提交. OK,没问题,我加了个ASPX页面,里面加了个FORM表单和一些元素,提交,返回值成功.注意看下面这一句:但返回值 ... 
- 【特征检测】BRISK特征提取算法
			[特征检测]BRISK特征提取算法原创hujingshuang 发布于2015-07-24 22:59:21 阅读数 17840 收藏展开简介 BRISK算法是2011年ICCV上< ... 
- win10下cuda安装以及利用anaconda安装pytorch-gpu过程
			安装环境:win10+2070super 1.Cuda的下载安装及配置 (1)测试本机独立显卡是否支持CUDA的安装,点击此处查询显卡是否在列表中. (2)查看自己是否能右键找到NVIDA控制面板,如 ... 
- numpy+sklearn 手动实现逻辑回归【Python】
			逻辑回归损失函数: from sklearn.datasets import load_iris,make_classification from sklearn.model_selection im ... 
- Nginx知多少系列之(十四)Linux下.NET Core项目Nginx+Keepalived高可用(主从模式)
			目录 1.前言 2.安装 3.配置文件详解 4.工作原理 5.Linux下托管.NET Core项目 6.Linux下.NET Core项目负载均衡 7.负载均衡策略 8.加权轮询(round rob ... 
- Java 创建 Excel 数据透视表
			Excel 数据透视表具有强大的数据处理功能,能够使表格中的数据更加直观化.使用Excel 数据透视表,能方便用户快速的排序. 筛选各种数据,同时也能满足用户对不同数据汇总的需求.本文将介绍如何在Ja ... 
