1、什么是POSIX标准
Portable Operating System Interface for Computing System.
他是一个针对操作系统(准确地说是针对类Unix操作系统)的标准化协议。
这个协议是对操作系统服务接口的标准化,从而保证了应用程序在源码层次的可移植性。
如今主流的Linux系统都做到了兼容POSIX标准。
2、POSIX标准的C/C++库
C/C++的标准库是指ANSI C/C++定义的标准库,这个是构成标准C/C++语言的基础。简称libc/libc++,常见的libc/libc++的实现有:UNIX C/C++,GUN C/C++,MicroSoft Visual C/C++ 在标准C/C++库基础上,兼容POSIX协议的C/C++库就是POSIX标准的C/C++库,这些C/C++库可以直接操作符合POSIX标准的操作系统调用。 常见的POSIX标准C/C++库有: 2.1 BSD,这个库是AOSP使用的标准C库。 2.2 Bionic,这个是BSD的衍生库,用于NDK开发 2.3 UNIX C/C++,GUN C/C++,MicroSoft Visual C/C++POSIX 进程间通信 (Interprocess Communication, IPC) 是 System V 进程间通信的变体。它是在 Solaris 7 发行版中引入的。与 System V 对象类似,POSIX IPC 对象的属主、属主的组以及其他用户具有读取和写入权限,但是没有执行权限。POSIX IPC 对象的属主无法将对象分配给其他属主。POSIX IPC 包括以下功能:
-
消息允许进程将已格式化的数据流发送到任意进程。
-
信号量允许进程同步执行。
-
共享内存允许进程共享其部分虚拟地址空间。
与 System V IPC 接口不同,POSIX IPC 接口均为多线程安全接口。
POSIX 消息
下表中列出了 POSIX 消息队列接口。
表 7-2 POSIX 消息队列接口
|
POSIX 信号量
POSIX 信号量比 System V 信号量轻得多。POSIX 信号量结构定义单个信号量,而不是定义最多包含 25 个信号量的数组。
POSIX 信号量接口如下所示。
- sem_open(3RT)
-
连接到以及(可选)创建命名信号量
- sem_init(3RT)
-
初始化信号量结构(在调用程序内部,因此不是命名信号量)
- sem_close(3RT)
-
结束到开放式信号量的连接
- sem_unlink(3RT)
-
结束到开放式信号量的连接,并在最后一个进程关闭此信号量时将其删除
- sem_destroy(3RT)
-
初始化信号量结构(在调用程序内部,因此不是命名信号量)
- sem_getvalue(3RT)
-
将信号量的值复制到指定整数中
- sem_wait(3RT)、sem_trywait(3RT)
-
当其他进程拥有信号量时进行阻塞,或者当其他进程拥有信号量时返回错误
- sem_post(3RT)
-
递增信号量计数
POSIX 共享内存
POSIX 共享内存实际上是映射内存的变体(请参见创建和使用映射)。二者的主要差异在于:
-
打开共享内存对象应使用 shm_open(3RT),而不是通过调用 open(2)。
-
关闭和删除对象应使用 shm_unlink(3RT),而不是通过调用 close(2),此调用不删除对象。
shm_open(3RT) 中的选项数实际上少于 open(2) 中提供的选项数。
POSIX共享内存
DESCRIPTION
共享内存是最快的可用IPC形式。它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存。
如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案。一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传输就不再涉及内核。这样就可以减少系统调用时间,提高程序效率。
共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。所有进程都可以访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会立刻被有访问同一段共享内存的其他进程看到。
要注意的是共享内存本身没有提供任何同步功能。也就是说,在第一个进程结束对共享内存的写操作之前,并没有什么自动功能能够预防第二个进程开始对它进行读操作。共享内存的访问同步问题必须由程序员负责。可选的同步方式有互斥锁、条件变量、读写锁、纪录锁、信号灯。
实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止。
POSIX Shared Memory API
使用POSIX共享内存需要用到下面这些API:
#include <sys/types.h> #include <sys/stat.h> /* For mode constants */ #include <sys/mman.h> #include <fcntl.h> /* For O_* constants */ #include <unistd.h> int shm_open(const char *name, int oflag, mode_t mode); int shm_unlink(const char *name); int ftruncate(int fildes, off_t length); void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); int munmap(void *addr, size_t len); int close(int fildes); int fstat(int fildes, struct stat *buf); int fchown(int fildes, uid_t owner, gid_t group); int fchmod(int fildes, mode_t mode);
shm_open
穿件并打开一个新的共享内存对象或者打开一个既存的共享内存对象, 与函数open的用法是类似的. 函数返回值是一个文件描述符,会被下面的API使用.
ftruncate
设置共享内存对象的大小,新创建的共享内存对象大小为0.
mmap
将共享内存对象映射到调用进程的虚拟地址空间.
munmap
取消共享内存对象到调用进程的虚拟地址空间的映射.
shm_unlink
删除一个共享内存对象名字.
close
当shm_open函数返回的文件描述符不再使用时,使用close函数关闭它.
fstat
获得共享内存对象属性的stat结构体. 结构体中会包含共享内存对象的大小(st_size), 权限(st_mode), 所有者(st_uid), 归属组 (st_gid).
fchown
改变一个共享内存对象的所有权.
fchmod
改变一个共享内存对象的权限.
Persistence(持续性)
POSIX 共享内存随内核持续: 共享内存对象会一直存在,直到系统关闭 或者 一个进程取消内存映射(unmapped)并且调用shm_unlink来删除共享内存对象.
Linking(链接库)
必须链接rt(librt)库,也就是real-time library.
-lrt
Accessing shared memory objects via the file system
在Linux系统中, 共享内存对象是在虚拟文件系统(tmpfs)中创建的, 通常挂载在目录 /dev/shm 下.
Linux从内核2.4 和glibc 2.2版本开始支持POSIX共享内存.
从Linux内核2.6.19版本起, Linux支持使用访问控制列表(ACLs) 来控制虚拟文件系统中对象的权限.
Inherit
to be continued...
CONFORMING TO(遵守的彼岸准)
POSIX.1-2001.
NOTES
多进程必须使用同步机制来访问共享内存对象, 比如使用POSIX信号量.
System V 的共享内存是过时的, POSIX共享内存提供了使用更简单、设计更合理的API.
- POSIX:
- 简介:
- 该模块包含了定义在 IEEE 1003.1(POSIX.1)标准文档里的函数的接口,通过其它手段无法访问。
- 警告:
- 通过POSIX函数,可以检索很多敏感数据,例如:posix_getpwnam()以及其它函数。当开启了安全模式,POSIX函数并不会执行任何的权限检测。因此,当正在上述的环境下操作,强烈建议关闭POSIX扩展(在配置行中使用 '--disable-posix')。
- 安装:
- POSIX函数默认是启用的,可通过 '--disable-posix' 来禁用POSIX函数
- 预定义常量,分3大类:
- posix_access_constants - 权限相关,php5.1.0开始支持:
- POSIX_F_OK - 检查文件是否存在
- POSIX_R_OK - 检查文件是否存在,且具有 '读' 权限
- POSIX_W_OK - 检查文件是否存在,且具有 '写' 权限
- POSIX_X_OK - 检查文件是否存在,且具有 '执行' 权限
- posix_mknod_constants - 文件类型,php5.1.0开始支持:
- POSIX_S_IFBLK - 块特殊文件
- POSIX_S_IFCHR - 字符特殊文件
- POSIX_S_IFIFO - FIFO(pipe-管道)特殊文件
- POSIX_S_IFREG - 普通文件
- POSIX_S_IFSOCK - socket
- posix_setrlimit_constants - php7.0.0开始支持:
- 你不妨看一下下面参考页,关于你的操作系统的setrlimit()的注意点,有关于实现POSIX的limits的差异的解释,甚至是跨操作系统的声明。
- POSIX_RLIMIT_AS - 进程地址空间的最大尺寸,单位是bytes。也可查看PHP的 'memory_limit' 配置指令
- POSIX_RLIMIT_CORE - 核心文件的最大尺寸。如果设置为0,将不会生成核心文件
- POSIX_RLIMIT_CPU - 进程可使用的CPU最大时间,单位是秒。当达到软限制(soft limit),将发送一个 'SIGXCPU' 信号,这个信号可以被 'pcntl_signal()' 捕获。依赖于操作系统,每秒都会发送额外的 'SIGXCPU' 信号,直到达到硬限制(hard limit),基于这点,会发送一个无法捕获的 'SIGKILL' 信号。也可查看 'set_time_limit()'
- POSIX_RLIMIT_DATA - 进程数据段的最大尺寸,单位是bytes。这基本不会对PHP的执行造成任何影响,除非使用了一个叫做 'brk()' 或 'sbrk()' 的扩展
- POSIX_RLIMIT_FSIZE - 进程可以创建的文件的最大尺寸,单位是bytes
- POSIX_RLIMIT_LOCKS - 进程可以创建的最大的锁定数量。仅支持非常老版的linux内核
- POSIX_RLIMIT_MEMLOCK - 内存中,可以锁定的最大字节数
- POSIX_RLIMIT_MSGQUEUE - 可以分配给 POSIX 消息队列的最大字节数。PHP不支持POSIX 消息队列,因此,这个限制没有任何影响,除非,你使用了一个实现了支持 'POSIX_RLIMIT_MSGQUEUE' 的扩展
- POSIX_RLIMIT_NICE - 进程可以设置 'renice'(linux进程的优先级之类的) 的最大值。值可以被设置为:20-我们设置的值,作为资源限制,不能设置为负
- POSIX_RLIMIT_NOFILE - 进程可以打开的 >(大于)最大文件描述符数字的值。
- POSIX_RLIMIT_NPROC - 进程的真实用户ID可以创建的进程(和线程、或者线程,在一些操作系统上)的最大个数。
- POSIX_RLIMIT_RSS - 进程的常驻集合的最大尺寸,单位是 pages
- POSIX_RLIMIT_RTPRIO - 通过 'sched_setscheduler()' 和 'sched_setparam()' 系统调用,可以设置的最大真实时间优先。
- POSIX_RLIMIT_RTTIME - 如果使用真实的时间调度,在不进行阻塞的系统调用下,进程可以消耗掉最大CPU时间,单位是微秒
- POSIX_RLIMIT_SIGPENDING - 进程的真实用户ID,可以设置的信号队列的最大个数
- POSIX_RLIMIT_STACK - 进程栈的最大尺寸,单位是bytes
- POSIX_RLIMIT_INFINITY - 用于指明资源大小不受限制(给资源限制设置了一个无限大值)。
- 函数:
- posix_access(string $file[, int $mode = POSIX_F_OK])
- 查看用户对文件是否具有指定的权限
- 参数:
- $file - 测试的文件名
- $mode - 权限,包含:POSIX_F_OK, POSIX_R_OK, POSIX_W_OK, POSIX_X_OK的一个或多个。
- posix_ctermid()
- 返回当前进程所在的当前控制终端的路径名
- 返回值:
- 成功时,返回路径名。否则返回false,并设置错误号。可通过 'posix_get_last_error()' 来获取
- posix_errno() - posix_get_last_error()别名
- posix_get_last_error()
- 检索最后的posix函数调用失败,返回的错误号。错误号关联的错误消息,可通过 'posix_strerror()' 来获取
- posix_strerror(int $errno)
- 通过给定的错误号,返回关联的POSIX系统错误消息
- posix_getcwd()
- 获取当前脚本的工作目录的绝对路径
- posix_getegid()
- 返回当前进程的有效用户组ID
- posix_geteuid()
- 返回当前进程的有效用户ID
- posix_getgid()
- 返回当前进程的真实用户组ID
- posix_getuid()
- 返回当前进程的真实用户ID
- posix_getgrgid(int $gid)
- 通过传入组ID,获取给定的用户组的相关信息
- posix_getgrnam(string $name)
- 通过传入组名称,获取给定的用户组的相关信息
- posix_getgroups()
- 获取当前进程的用户组集合
- 返回值:
- 返回一个索引数组,包含组id的集合
- posix_getlogin()
- 返回拥有当前进程的用户的登陆名
- 示例:
- <?php
- echo posix_getlogin(); // apache
- ?>
- posix_getpgid(int $pid)
- 获取指定进程的进程组标识符(进程组id),返回整数
- 注意:
- 该函数不是POSIX函数,但是常见于BSD和System V的系统上。如果系统不支持该函数,在编译时就不会被包含进来。应该提前使用 'function_exists()' 检查,存在再使用
- posix_getpgrp()
- 获取当前进程的进程组标识符(进程组id),返回整数
- 可查看:POSIX.1 和 POSIX系统上的getpgrp(2) 帮助手册,获取关于进程组的更多信息
- posix_getpid()
- 获取当前进程的进程标识符(进程id)
- posix_getppid()
- 获取当前进程的父进程标识符(父进程id)
- posix_getpwnam(string $username)
- 通过用户名,获取给定用户的信息
- 返回值:
- 成功,返回一个关联数组,下标如下,失败返回false:
- name - 是一个短的、通常少于16个字符,非真实的、全名。应该同调用函数时,传递的$username参数一致,截断多余的字符
- passwd - 返回加密后的用户密码的字符串。通常,例如系统的shadow密码,使用 '*' 代替
- uid - 用户ID
- gid - 用户组ID。使用 posix_getgrgid() 获取用户组名和它的成员列表
- gecos - 一个过时的元素,包含了 ',' 分隔的用户的全名、办公室电话、办公室号码以及家庭电话号码。大多数的系统上,只有用户的全名有效。
- dir - 用户家目录的绝对路径
- shell - 可执行的用户的默认shell的绝对路径
- 示例:
- <?php
- $userinfo = posix_getpwnam('tom');
- print_r($userinfo);
- ?>
- 输出:
- Array(
- [name] => tom
- [passwd] => x
- [uid] => 10000
- [gid] => 42
- [gecos] => "tom,,," // ',' 分隔
- [dir] => "/home/tom"
- [shell] => "/bin/bash"
- )
- posix_getpwuid(int $uid)
- 通过用户id,获取给定用户的信息
- posix_getrlimit()
- 返回一个关于当前资源的软限制和硬限制的信息数组
- 每个资源有一个关联的软限制和硬限制。
- 软限制-查看linux系统
- 硬限制-查看linux系统
- 一个无特权的进程,可能只能设置它的软限制为:0-硬限制大小,并且必须低于硬限制的值。
- 返回值:
- 返回一个关联数组,下标为定义的各种限制。每个限制都有一个软限制和硬限制。
- core - 核心文件的最大尺寸。当为0,不会创建核心文件。核心文件大于该设定值,将会被截断
- totalmem - 进程的内存最大值,单位为bytes
- virtualmem - 进程的虚拟内容的最大值,单位为bytes
- data - 进程的数据段的最大值,单位为bytes
- stack - 进程栈的最大值,单位为bytes
- rss - RAM中常驻的虚拟页面的最大个数
- maxproc - 可被调用进程的真实用户ID创建的最大进程数量
- memlock - 在RAM中,可被锁定的内存的最大字节数
- cpu - 进程允许使用的最大CPU时间
- filesize - 进程可以创建的文件的最大尺寸,单位是bytes
- openfiles - 进程可以打开的最大文件数量
- 示例:
- <?php
- $limits = posix_getrlimit();
- print_r($limits);
- ?>
- 输出:
- Array(
- [soft core] => 0
- [hard core] => unlimited
- [soft data] => unlimited
- [hard data] => unlimited
- [soft stack] => 8388608
- [hard stack] => unlimited
- )
- posix_getsid(int $pid)
- 返回指定进程的session ID。进程的session ID是会话领导者(session leader)的进程组id
- posix_initgroups(string $name, int $base_group_id)
- 对指定的用户,计算其组访问列表
- 参数:
- $name - 指定的用户名
- $base_group_id - 密码文件里的组ID
- posix_isatty(mixed $fd)
- 检查文件描述符是否是一个有效的终端类型的设置(是否是tty)
- 参数:
- $fd - 文件描述符,期望是一个文件资源或一个整型。整型将被假定为可以直接传递到基础系统调用的文件描述符。几乎在所有情况下,提供的是一个文件资源。
- posix_kill(int $pid, int $sig)
- 给指定的进程发送一个$sig指定的信号!
- 参数:
- $pid - 进程id
- $sig - PCNTL信号预定义常量
- posix_mkfifo(string $pathname, int $mode)
- 创建一个特殊的FIFO文件,存在于文件系统,并且作为进程的双向通信桥梁
- 参数:
- $pathname - FIFO文件(管道)
- $mode - 必须是8进制格式。新创建的FIFO的权限,也依赖于当前的umask()设置。新创建的文件权限是(mode & ~umask)
- posix_mknod(string $pathname, int $mode[, int $major = 0[, int $minor = 0]])
- 创建一个特殊的或者一般的文件
- 参数:
- $pathname - 创建的文件
- $mode - 这个参数由文件类型(POSIX_S_IFREG, POSIX_S_IFCHR, POSIX_S_IFBLK, POSIX_S_IFIFO, POSIX_S_IFSOCK其中一个)和访问权限(0664等),按位或组成。
- $major - 主设备内核标识符(当使用S_IFCHR或S_IFBLK时,需要传递该参数)
- $minor - 监控设备内核标识符
- posix_setegid(int $gid)
- 设置当前进程的有效组ID。这是个特权函数,需要操作系统上具有特殊权限(通常是root权限),才能执行该函数。
- posix_seteuid(int $uid)
- 设置当前进程的有效用户ID。这是个特权函数,需要操作系统上具有特殊权限(通常是root权限),才能执行该函数。
- posix_setgid(int $gid)
- 设置当前进程的真实用户组ID。这是个特权函数,需要操作系统上具有特殊权限(通常是root权限),才能执行该函数。函数调用的适当的顺序是:首先调用 posix_setgid(),最后调用 posix_setuid()。
- 注意:
- 如果是超级用户调用,也会设置有效用户组ID
- posix_setpgid(int $pid, int $pgid)
- 设置指定进程的进程组ID
- posix_setrlimit(int $resource, int $softlimit, int $hardlimit)
- 设置给定系统资源的软限制和硬限制。
- 参数:
- $resource - 是posix_setrlimit_constants预定义常量
- $softlimit - 软限制,任意设置或者 POSIX_RLIMIT_INFINITY - 无限大
- $hardlimit - 硬限制,任意设置或者 POSIX_RLIMIT_INFINITY - 无限大
- posix_setsid()
- 设置当前进程为session leader(会话领导者)
- posix_setuid(int $uid)
- 设置当前进程的真实用户ID。这是个特权函数,需要操作系统上具有特殊权限(通常是root权限),才能执行该函数。
- posix_times()
- 获取当前CUP使用信息
- 返回值:
- 返回一个关联数组
- ticks - 重启到现在,已经过去的 clock ticks 个数
- utime - 当前进程使用的用户时间
- stime - 当前进程使用的系统时间
- cutime - 当前进程和子进程使用的用户时间
- cstime - 当前进程和子进程使用的系统时间
- 警告:
- 函数不可靠,对于高时间(high times)可能返回负值。
- posix_ttyname($mixed $fd)
- 返回当前打开的文件描述符所在的终端设备的绝对路径
- 参数:
- $fd - 文件描述符,期望是一个文件资源或一个整型。整型将被假定为可以直接传递到基础系统调用的文件描述符。几乎在所有情况下,提供的是一个文件资源。
- posix_uname()
- 获取系统相关信息。
- 返回值:
- 返回一个关于系统信息的关联数组
- sysname - 操作系统名称(例如:Linux)
- nodename - 系统名称(例如:valiant)
- release - 操作系统的发布版(例如:2.6.15-1-686)
- version - 操作系统版本(例如:#4 Tue Jul 20 17:01:36 MEST 1999)
- machine - 系统平台(例如:i586)
- domainname - DNS域名(例如:baidu.com)
-
在linux操作系统中,实现了两类对文件IO的管理,一类是遵循POSIX标准,linux操作系统自身提供的IO系统调用,如open、close、read等函数;另一类是由ANSI标准提供的标准IO库函数,这些函数是对直接IO系统调用的封装,其在访问文件时根据需要设置了不同类型的缓冲区,从而减少了直接IO系统调用的次数,提高访问效率。
1、 文件流与文件描述符的区别:
使用ANSI C函数fopen打开的文件对应一个流文件,任何进程在运行的时候,都默认打开了3个流对象。对于用户空间来说,任何打开的文件都将被分配一个唯一非整数,用于标识该打开文件,该值即文件描述符。
2、 文件描述符与文件流的转换操作:
Linux为用户层提供了函数fileno()以从文件流中读取其文件描述符,即获得struct FILE的_fileno成员
Int fileno (FILE *_stream) 此函数以某个流对象为参数,返回该流的文件描述符值。
FILE *fdopen(int _fd,_const char *_modes) 此函数第一个参数为一个文件描述符,第2个参数为封装该流的权限。
3、 POSIX标准下文件IO管理:
1)、打开文件
Int open(_const char *file,int _oflag,…) 第1个参数为欲打开文件的路径,第2个参数为打开文件的方式,第3个参数可有可无,自动创建该文件,它规定了文件的权限。
2)、关闭文件
Int close(int _fd)关闭文件,将相应的内容全部写回文件中,即让数据写回磁盘。
3)、创建文件
Int creat(_const char *_file,_mode_t _mode) 第1个参数为欲创建文件的路径,第2个参数为该文件的访问权限。
4)、文件控制
Int fcntl(int _fd,int _cmd) 第1个参数fd为欲修改属性的文件描述符,第2个参数cmd为相应的操作,常用命令如下:
#define F_DUPFD 0 //复制文件描述符
#define F_GETFD 1 //获得文件描述符标志
#define F_SETFD 2 //设置文件描述符标志
#define F_GETFL 3 //获取文件状态
#define F_SETFL 4 //设置文件状态
5)、读文件内容
Ssize_t read (int _fd,void *_buf,size_t _nbytes)
从参数fd所指的文件中读取_nbytes数据到buf指针所指的内存中。
6)、写内容到文件
Ssize_t write (int _fd , _const void *_buf , size_t _n)
将buf为起始地址的缓冲区前n个字节写入与打开文件描述符fd关联的文件内。
7)、文件定位
_off_t lseek(int _fd , _off_t _offset , int _whence)
第1个参数为已经打开的文件,第2个参数offset为位移数,第3个参数为参考点。
8)、同步内核缓冲区
为了保证磁盘上实际文件系统与缓存中的内容的一致性,sync、fsync和fdatasync系统调用可以更新缓冲区。
Void sync(void) 将所有修改写的块的缓存排入写队列,然后返回,不等待实际IO操作结束。
Int fsync(int fildes) 等待IO结束,然后返回,多用于于数据库相关的应用程序,它确保修改过的块立即写到磁盘上。
Int fdatasync(int fildes) 只更新内容。
4、 目录文件基本操作
1)、打开目录文件
DIR *opendir(const char *dirname) 打开路径为dirname 的目录,并使一个目录流与它相关联。
2)、关闭目录文件
int closedir(DIR *dirp) 关闭指定的目录流,然后释放与DIR指针关联的结构
3)、读目录内容
Struct dirent *readdir(DIR *dirp) 读取该目录下的文件列表,该函数的返回类型为struct dirent。
Int readdir_r (DIR *dirp ,struct dirent *entry, struct dirent **result) 实现多线程读取目录内容操作
4)、定位目录位置
Long int telldir(DIR *dirp) 目录流相关联的当前位置
Void seekdir(DIR *dirp , long int loc) 类似于文件定位函数fseek(),在目录流上设置下一个readdir()操作的位置。
5)、添加删除目录
Int mkdir(_const char *_path, _mode_t _mode) 第1个参数为欲创建的目录文件路径,
第2个参数为该目录的访问权限
Int rmdir(_const char *_path) 参数为欲删除目录的位置
6)、当前工作路径操作
a)、获取当前工作路径
char *getcwd (char *_buf , size_t _size) //获取当前工作路径到buf中,
如果设置buf为NULL,getcwd()将利用malloc()获取空间,在此情况下,由getcwd()返回的指针需要被释放。
Char *get_current_dir_name(void) 返回当前绝对路径
b)、修改当前工作路径
int chdir (_const char *_path) //修改进程工作路径,参数为目录路径