Web服务器踩坑之旅:04定位服务器上的文件资源

项目地址:https://github.com/lanofblue/SimpleWebServer

本文实现的文件在源码中的SimpleWebServer/file_manager目录下

本文内容:定位服务器上的文件并获取文件内容

  • 定位文件
  • 获取文件信息和内容

上一篇文章中,我们已经解析了HTTP请求报文,并将文件名存入http_parser::m_url中,那么我们接下来要在服务器中定位文件,并得到它的内容。在此项目中,我设定的服务器主页是homepage.html文件,那么以访问该文件为例。若访问网站的主页,经HTTP_parser解析,我们可以得到m_url = "homepage.html";

定位文件

首先定义网站的根目录:这是客户端能够访问到的服务器的最顶层目录。客户端只能访问该目录下的子目录,不能访问其上层目录,如SimpleServer目录。

const char* doc_root = "/home/blue/SimpleServer/root";

homepage.html文件存放在root目录里,因此homepage.html在服务器中的文件路径即为

/home/blue/SimpleServer/root/homepage.html

定义m_real_file来存放此路径:

strcpy(m_real_file, doc_root);
int len = strlen(doc_root);
strncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);

获取文件信息和内容

文件基本信息

在Linux系统中,文件的信息通过以下结构体保存

struct stat {
mode_t    st_mode;    // protection:客户是否有查看此文件的权限
off_t     st_size;    /* total size, in bytes:要传输的文件大小

// 在本项目中我们只关心上面两个成员
dev_t     st_dev;     /* ID of device containing file */
ino_t     st_ino;     /* inode number */
nlink_t   st_nlink;   /* number of hard links */
uid_t     st_uid;     /* user ID of owner */
gid_t     st_gid;     /* group ID of owner */
dev_t     st_rdev;    /* device ID (if special file) */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
time_t    st_atime;   /* time of last access */
time_t    st_mtime;   /* time of last modification */
time_t    st_ctime;   /* time of last status change */
};

获取文件内容

我们要获取文件内容,必须建立文件与内存的映射

下面说一下内存映射的步骤:
open系统调用打开文件, 并返回描述符fd
mmap建立内存映射, 并返回映射首地址指针start
对映射(文件)进行各种操作, 显示(printf), 修改(sprintf)
munmap(void *start, size_t lenght)关闭内存映射
close系统调用关闭文件fd

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset); 
int munmap(void* start,size_t length);
mmap函数的参数描述
start指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址
length代表将文件中多大的部分映射到内存
prot映射区域的保护方式
flags影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHAREDMAP_PRIVATE
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
fd要映射到内存中的文件描述符
offset文件映射的偏移量

返回值:

若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中

(内存映射的内容比较复杂,详情可阅读这篇博客Linux 内存映射函数 mmap()函数详解)

根据以上步骤我们可以实现如下获取文件资源的函数

HTTP_CODE file_manager::locate_file() {
    // 获取文件在服务器上的完整路径
    strcpy(m_real_file, doc_root);
    int len = strlen(doc_root);
    strncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);
    
    // 获取文件基本信息
    if (stat(m_real_file, &m_file_stat) < 0) {      // 文件不存在
        return NO_RESOURCE;
    }
    
    // 检查权限
    if (!(m_file_stat.st_mode & O_RDONLY)) {        // 无权读取文件
        return FORBIDDEN_REQUEST;
    }
    
    // 检查文件类型
    if (S_ISDIR(m_file_stat.st_mode)) {             // 文件类型是目录
        return BAD_REQUEST;
    }
    
    // 建立文件内存映射
    int fd = open(m_real_file, O_RDONLY);
    m_file_address = (char*)mmap(0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
    return FILE_REQUEST;
}

经过以上的操作,m_file_address指向了文件在内存中的起始位置,m_file_stat.st_size是文件的大小(字节),知道这两个重要的参数即可传输该文件的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值