【问题标题】:system call to map memory to a file descriptor (inverse mmap)?将内存映射到文件描述符(反向 mmap)的系统调用?
【发布时间】:2011-02-18 19:20:12
【问题描述】:

我希望能够将内存映射到文件描述符,这样我就可以使用一些需要文件描述符的现有函数。这基本上就是我要找的东西:

void do_operation1(int fd);

char data[DATA_MAX] = { /* embedded binary data */ };
int fd = addr_to_fd(data, DATA_MAX);

do_operation1(fd);
/* ... operate on fd ... */

我可以使用什么系统调用或调用来完成此操作?

【问题讨论】:

    标签: c unix posix mmap system-calls


    【解决方案1】:

    一些实现有fmemopen()。 (那你当然得打电话给fileno())。

    如果您没有,您可以使用 fork()pipe() 自行构建。

    【讨论】:

    • FILE* 来自fmemopen 或类似的东西时,fileno() 在 Linux/FreeBSD(我猜是其他人)上都失败了。如果无法获取文件描述符,我不确定我们是否有解决方案。
    • fmemopen 也可以在 BSD 上使用 funopen 来实现。 redmine.openinfosecfoundation.org/attachments/105/… 提供了一种实现
    • fork() 对于这个目的来说是相当重量级的。我建议改用线程。使用select() 在管道读取和写入之间进行多路复用会更好,但我想这不是一个选项。
    • 这行不通,因为fmemopen() 只是创建了一个由给定内存缓冲区支持的FILE*。没有创建文件描述符。
    【解决方案2】:

    您应该查看shm_open()

    【讨论】:

      【解决方案3】:

      当然,只需open(argv[0], ...),扫描文件以查找二进制数据的开始位置,lseek() 在那里完成。当然,那个文件不会有你的二进制数据的长度。

      【讨论】:

        【解决方案4】:

        您不能将“一些现有的内存缓冲区”映射到文件描述符。 正如上面评论中所说,fmemopen() 函数将内存缓冲区与“FILE *”流指针相关联,该指针可以使用 libc 提供的流函数进行操作。未分配文件描述符:“FILE *”流是高级抽象,与作为低级句柄的文件描述符不兼容。

        相反,您可能希望分配一个新的共享内存缓冲区并将其映射到文件描述符。这被广泛使用,在 Linux 术语中称为“内存映射文件”。

        您可以使用通过open() 获得的文件描述符来引用文件,或者使用通过shm_open() 获得的文件描述符来引用共享内存对象。任何文件描述符句柄都可以完成这项工作。然后您可以调用mmap() 将文件描述符映射到共享内存缓冲区。

        注意:如果文件描述符引用非常规文件,例如管道、套接字或字符设备文件(例如,/dev/ttys001),mmap() 将失败。因此,您通常无法为 STDIN、STDOUT 或 STDERR 文件描述符创建内存映射文件。

        您可以以类似数组的方式操作内存缓冲区,并将对内存映射文件的修改提交到磁盘。反之亦然,对文件所做的任何修改(例如,使用write() 系统调用)也会提交到内存。


        下面的 sn -p 打开一个您选择的文件并将其映射到内存中。它将打印前 256 个字符并将它们替换为原始文件中的“*”。在符合 POSIX 的系统上使用 cc mmap_test.c -o mmap_test 编译它。

        #include <fcntl.h>
        #include <stdio.h>
        #include <string.h>
        #include <sys/mman.h>
        #include <sys/types.h>
        #include <unistd.h>
        
        int main(int ac, char *av[])
        {
            int pagesize, fd;
            unsigned char *data;
        
            if ( ac < 2 ) {
                printf("Usage: %s <filepath>\n", av[0]);
                return 1;
            }
        
            pagesize = getpagesize();
        
            if ( (fd = open(av[1], O_RDWR)) == -1 ) {
                perror("Error: cannot open file for reading");
                return 1;
            }
        
            if ( (data = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED ) {
                perror("Error: cannot create memory-mapped file");
                return 1;
            }
        
            write(1, data, 256);
            memset(data, '*', 256);
        
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-08
          • 2017-02-12
          • 2011-07-30
          • 1970-01-01
          • 2023-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多