【Nginx】磁盘文件写入飞地发
文章继续。什么时候Nginx当用户请求一个文件,这将无法读取该文件的内容加载到内存,然后从内存发送,但电话sendfile况下,从内核直接发送出去。这样做显然效率要更高。Nginx也为我们封装好了一系列的接口。以下就来说明怎样发送一个磁盘文件给client。
struct ngx_buf_s {
....
off_t file_pos; // 文件起始位置
off_t file_last; // 文件结束位置
....
ngx_file_t *file; // 引用的文件
....
};
typedef struct ngx_file_s ngx_file_t;
struct ngx_file_s {
ngx_fd_t fd; // 文件描写叙述符
ngx_str_t name; // 文件名称
ngx_file_info_t info; // 文件相关信息,相当于stat结构体 off_t offset; // 告诉Nginx处理到文件何处了。一般不使用
off_t sys_offset; // 文件偏移量,一般不使用 ngx_log_t *log; // 日志对象 #if (NGX_HAVE_FILE_AIO)
ngx_event_aio_t *aio;
#endif unsigned valid_info:1; // 未使用
unsigned directio:1; // 发送大文件时设为1
};
struct ngx_pool_cleanup_s {
ngx_pool_cleanup_pt handler; // 运行实际清理工作的回调方法
void *data; // 回调方法的參数
ngx_pool_cleanup_t *next; // 下一个清理对象
};
// 用于告诉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; cln->handler = ngx_pool_cleanup_file; // ngx_pool_cleanup_file专用于关闭文件句柄 ngx_pool_cleanup_file_t *clnf = cln->data; // cln->data为上述回调函数的參数
clnf->fd = b->file->fd;
clnf->name = b->file->name.data;
clnf->log = r->pool->log;
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);
}
}
typedef struct {
ngx_fd_t fd; // 文件描写叙述符
u_char *name; // 文件名称
ngx_log_t *log; // 日志对象
} ngx_pool_cleanup_file_t;
- ngx_buf_t.ngx_file_t.df
- ngx_buf_t.ngx_file_t.name
- ngx_buf_t.ngx_file_t.log
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h> static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r); static ngx_command_t ngx_http_mytest_commands[] =
{
{
ngx_string("mytest"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
ngx_http_mytest,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
}, ngx_null_command
}; static ngx_http_module_t ngx_http_mytest_module_ctx =
{
NULL, /* preconfiguration */
NULL, /* postconfiguration */ NULL, /* create main configuration */
NULL, /* init main configuration */ NULL, /* create server configuration */
NULL, /* merge server configuration */ NULL, /* create location configuration */
NULL /* merge location configuration */
}; ngx_module_t ngx_http_mytest_module =
{
NGX_MODULE_V1,
&ngx_http_mytest_module_ctx, /* module context */
ngx_http_mytest_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
}; static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf; // 首先找到mytest配置项所属的配置块,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与mytest配置项所在的配置块相匹配,就将调用我们
// 实现的ngx_http_mytest_handler方法处理这个请求
clcf->handler = ngx_http_mytest_handler; return NGX_CONF_OK;
} static ngx_int_t ngx_http_mytest_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 *b;
b = ngx_palloc(r->pool, sizeof(ngx_buf_t)); u_char* filename = (u_char*)"/tmp/test.txt"; // 要打开的文件名称
b->in_file = 1; // 设置为1表示缓冲区中发送的是文件 // 分配代表文件的结构体空间。file成员表示缓冲区引用的文件
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; // name成员表示文件名称称
b->file->name.len = sizeof(filename) - 1;
if (b->file->fd <= 0)
return NGX_HTTP_NOT_FOUND; r->allow_ranges = 1; //支持断点续传 // 获取文件长度,ngx_file_info方法封装了stat系统调用
// info成员就表示stat结构体
if (ngx_file_info(filename, &b->file->info) == NGX_FILE_ERROR)
return NGX_HTTP_INTERNAL_SERVER_ERROR; // 设置缓冲区指向的文件块
b->file_pos = 0; // 文件起始位置
b->file_last = b->file->info.st_size; // 文件结束为止 // 用于告诉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; cln->handler = ngx_pool_cleanup_file; // ngx_pool_cleanup_file专用于关闭文件句柄 ngx_pool_cleanup_file_t *clnf = cln->data; // cln->data为上述回调函数的參数
clnf->fd = b->file->fd;
clnf->name = b->file->name.data;
clnf->log = r->pool->log; // 设置返回的Content-Type
// 注意,ngx_str_t有一个非常方便的初始化宏
// ngx_string,它能够把ngx_str_t的data和len成员都设置好
ngx_str_t type = ngx_string("text/plain"); //设置返回状态码
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = b->file->info.st_size; // 正文长度
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;
out.buf = b;
out.next = NULL; //最后一步发送包体,http框架会调用ngx_http_finalize_request方法
return ngx_http_output_filter(r, &out);
}
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmVzdGxlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
版权声明:本文博客原创文章,博客,未经同意,不得转载。
【Nginx】磁盘文件写入飞地发的更多相关文章
- 通过python操作GeoLite2-City.mmdb库将nginx日志访问IP转换为城市写入数据库
通过python操作GeoLite2-City.mmdb库将nginx日志写入数据库 # 创建存放nginx日志的表accesslog2 CREATE TABLE `accesslog2` ( `id ...
- Nginx基本属性配置详解
1. Nginx服务的基本配置 1.1 用于调试进程和定位问题的配置项 是否以守护进程的方式运行nginx # 默认on daemon on|off; 是否以master/worker方式工作 # 默 ...
- Linux -- nginx
一. 网络服务 web服务器和web框架的关系 web服务器(nginx):接收HTTP请求(例如www.baidu.com)并返回数据 web框架(django,flask):开发web应用程序,处 ...
- Nginx学习总结:常用module(二)
斜体下划线,表示建议采用默认配置,无需显式的配置 一.ngx_core_module 1.accept_mutex [on | off] 上下文:events 默认为“on”,在wor ...
- ubuntu 安装flask+nginx+gunicorn 待定
第一步 先检查服务器环境 pip python3 mysql redis 能下就下,该升级就升级 第二步 如果你的flask程序在github上 请使用git clone 地址 下载下来(如果是私 ...
- linux--配置开发环境 --Nginx篇
安装: 安装好了话,我们的nginx的目录在: /etc/nginx 启动: sudo service nginx start 然后访问我们的页面就可以看到了我们的界面 然后我们配置我们的域名: 我 ...
- 005.nginx配置文件
1.替换nginx主配置文件 通过前面的配置,LNMP的环境已经搭建完成,现在我们替换nginx配置文件: [root@huh ~]# cd /usr/local/nginx/conf/[root@h ...
- linux下利用GPRS模块发短信、打电话
一.开发环境 内核版本:linux-3.0 开发板:FL2440(nandflash:K9F1G08 128M) GPRS模块:SIM900 二.与发短信和拨号相关的 AT 指 ...
- PHP通过串口发短信
随技术进步,短信收发领域按时间先后产生了三种模式:BLOCK MODE,基于AT指令的TEXT MODE,基于AT指令的PDU MODE.其中,TEXT MODE比较简单,多款诺基亚手机均支持此款模式 ...
随机推荐
- 为什么国外程序员爱用苹果Mac电脑?(转)
Mac 在国外很受欢迎,尤其是在 设计/web开发/IT 人员圈子里.普通用户喜欢 Mac 可以理解,毕竟 Mac 设计美观,简单好用,没有病毒.那么为什么专业人士也对 Mac 情有独钟呢?从个人使用 ...
- swift-switch使用方法
// Playground - noun: a place where people can play import UIKit //--------------------------------- ...
- 使用WIX打包客户端程序
原文:使用WIX打包客户端程序 用WPF为客户做了个小工具,打包的时候发现VS2012居然没有安装项目了,搜了下才知道现在推荐使用WIX来打包了http://wix.sourceforge.net/, ...
- QT怎样在QTableWidge显示图片
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">QTableWi ...
- c#事件委托
转载地址:http://www.cnblogs.com/wudiwushen/archive/2010/04/20/1703368.html 从序言中,大家应该对委托和事件的重要性有点了解了吧, ...
- MySQL将表a中查询的数据插入到表b中
MySQL将表a中查询的数据插入到表b中 假设表b存在 insert into b select * from a; 假设表b不存在 create table b as select * from a ...
- Hadoop Spark 集群简便安装总结
本人实际安装经验,目的是为以后高速安装.仅供自己參考. 一.Hadoop 1.操作系统一如既往:①setup关掉防火墙.②vi /etc/sysconfig/selinux,改SELINUX=disa ...
- mindmanager2012打开文件出现runtime error r6025 解决方式
关于mindmanager 2012启动无法执行,提示c++错误 ---------------------------Microsoft Visual C++ Runtime Library---- ...
- 经典回忆Effective C++ 1
c++ 联邦语言: typedef { unit C; unit Object-Oriented C++; unit Template C++; unit STL; }; notice: C++高效编 ...
- EF 分离实体
具体步骤: 新建测试项目:如图 其中Respository和Model层均为类库项目, 1.在Respository层添加ADO.NET实体数据模型, 2.复制Model.tt文件到Model层,这是 ...