(apue学习)第一章 UNIX基础知识

UNIX体系结构

可将操作系统定义为一种软件,控制硬件资源,提供程序运行环境。通常称之为内核
UNIX操作系统体系结构:
(apue学习)第一章 UNIX基础知识_第1张图片
内核的接口被称为系统调用。公用函数库构建在系统调用接口之上,应用程序既可使用公用函数库,也可使用系统调用。shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口。

文件和目录

UNIX中一切皆文件,文件在Unix环境中是非常重要的东西,Unix文件系统就是一个虚拟层次结构,所有目录都挂载于/根目录,文件夹也可以被认为是一种文件,设备也是一种文件。
斜线(/)和空字符不能出现在文件名中,斜线用来分隔构成路径名的各文件名,空字符则用来终止一个路径名。文件系统根的名字(/)是一个特殊的绝对路径名,它不包含文件名。

输入和输出

1、文件描述符
通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,它都返回一个稳健描述符。在读写文件时,可以使用这个描述符。

两个常量STDIN_FILENO和STDOUT_FILENO定义在

程序和进程

程序是一个存储在磁盘上某个目录中的可执行文件,程序的执行实例被称为进程。

线程和线程ID

一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一储存区,各线程在访问共享数据时需要采取同步措施以避免不一致性。
线程ID只在它所属的 进程中起作用

出错处理

当UNIX系统出错时,通常会返回一个负值,设置在整形变量errno
文件

       E2BIG           Argument list too long (POSIX.1)

       EACCES          Permission denied (POSIX.1)

       EADDRINUSE      Address already in use (POSIX.1)

       EADDRNOTAVAIL   Address not available (POSIX.1)

       EAFNOSUPPORT    Address family not supported (POSIX.1)

       EAGAIN          Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1)

       EALREADY        Connection already in progress (POSIX.1)

       EBADE           Invalid exchange

       EBADF           Bad file descriptor (POSIX.1)

       EBADFD          File descriptor in bad state

       EBADMSG         Bad message (POSIX.1)

       EBADR           Invalid request descriptor

       EBADRQC         Invalid request code

       EBADSLT         Invalid slot

       EBUSY           Device or resource busy (POSIX.1)

       ECANCELED       Operation canceled (POSIX.1)

       ECHILD          No child processes (POSIX.1)

       ECHRNG          Channel number out of range

       ECOMM           Communication error on send

       ECONNABORTED    Connection aborted (POSIX.1)

       ECONNREFUSED    Connection refused (POSIX.1)

       ECONNRESET      Connection reset (POSIX.1)

       EDEADLK         Resource deadlock avoided (POSIX.1)

       EDEADLOCK       Synonym for EDEADLK

       EDESTADDRREQ    Destination address required (POSIX.1)

       EDOM            Mathematics argument out of domain of function (POSIX.1, C99)

       EDQUOT          Disk quota exceeded (POSIX.1)

       EEXIST          File exists (POSIX.1)

       EFAULT          Bad address (POSIX.1)

       EFBIG           File too large (POSIX.1)

       EHOSTDOWN       Host is down

       EHOSTUNREACH    Host is unreachable (POSIX.1)

       EIDRM           Identifier removed (POSIX.1)

       EILSEQ          Illegal byte sequence (POSIX.1, C99)

       EINPROGRESS     Operation in progress (POSIX.1)

       EINTR           Interrupted function call (POSIX.1); see signal(7).

       EINVAL          Invalid argument (POSIX.1)

       EIO             Input/output error (POSIX.1)

       EISCONN         Socket is connected (POSIX.1)

       EISDIR          Is a directory (POSIX.1)

       EISNAM          Is a named type file

       EKEYEXPIRED     Key has expired

       EKEYREJECTED    Key was rejected by service

       EKEYREVOKED     Key has been revoked

       EL2HLT          Level 2 halted

       EL2NSYNC        Level 2 not synchronized

       EL3HLT          Level 3 halted

       EL3RST          Level 3 halted

       ELIBACC         Cannot access a needed shared library

       ELIBBAD         Accessing a corrupted shared library

       ELIBMAX         Attempting to link in too many shared libraries

       ELIBSCN         lib section in a.out corrupted

       ELIBEXEC        Cannot exec a shared library directly

       ELOOP           Too many levels of symbolic links (POSIX.1)

       EMEDIUMTYPE     Wrong medium type

       EMFILE          Too many open files (POSIX.1); commonly caused by exceeding the RLIMIT_NOFILE  resource  limit  described  in  getr‐
                       limit(2)

       EMLINK          Too many links (POSIX.1)

       EMSGSIZE        Message too long (POSIX.1)

       EMULTIHOP       Multihop attempted (POSIX.1)

       ENAMETOOLONG    Filename too long (POSIX.1)

       ENETDOWN        Network is down (POSIX.1)

       ENETRESET       Connection aborted by network (POSIX.1)

       ENETUNREACH     Network unreachable (POSIX.1)

       ENFILE          Too  many open files in system (POSIX.1); on Linux, this is probably a result of encountering the /proc/sys/fs/file-
                       max limit (see proc(5)).

       ENOBUFS         No buffer space available (POSIX.1 (XSI STREAMS option))

       ENODATA         No message is available on the STREAM head read queue (POSIX.1)

       ENODEV          No such device (POSIX.1)

       ENOENT          No such file or directory (POSIX.1)

       ENOEXEC         Exec format error (POSIX.1)

       ENOKEY          Required key not available

       ENOLCK          No locks available (POSIX.1)

       ENOLINK         Link has been severed (POSIX.1)

       ENOMEDIUM       No medium found

       ENOMEM          Not enough space (POSIX.1)

       ENOMSG          No message of the desired type (POSIX.1)

       ENONET          Machine is not on the network

       ENOPKG          Package not installed

       ENOPROTOOPT     Protocol not available (POSIX.1)

       ENOSPC          No space left on device (POSIX.1)

       ENOSR           No STREAM resources (POSIX.1 (XSI STREAMS option))

       ENOSTR          Not a STREAM (POSIX.1 (XSI STREAMS option))

       ENOSYS          Function not implemented (POSIX.1)

       ENOTBLK         Block device required

       ENOTCONN        The socket is not connected (POSIX.1)

       ENOTDIR         Not a directory (POSIX.1)

       ENOTEMPTY       Directory not empty (POSIX.1)

       ENOTSOCK        Not a socket (POSIX.1)

       ENOTSUP         Operation not supported (POSIX.1)

       ENOTTY          Inappropriate I/O control operation (POSIX.1)

       ENOTUNIQ        Name not unique on network

       ENXIO           No such device or address (POSIX.1)

       EOPNOTSUPP      Operation not supported on socket (POSIX.1)

                       (ENOTSUP and EOPNOTSUPP have the same value on Linux, but according to POSIX.1 these error  values  should  be  dis
                       tinct.)

       EOVERFLOW       Value too large to be stored in data type (POSIX.1)

       EPERM           Operation not permitted (POSIX.1)

       EPFNOSUPPORT    Protocol family not supported

       EPIPE           Broken pipe (POSIX.1)

       EPROTO          Protocol error (POSIX.1)

       EPROTONOSUPPORT Protocol not supported (POSIX.1)

       EPROTOTYPE      Protocol wrong type for socket (POSIX.1)

       ERANGE          Result too large (POSIX.1, C99)

       EREMCHG         Remote address changed

       EREMOTE         Object is remote

       EREMOTEIO       Remote I/O error

       ERESTART        Interrupted system call should be restarted

       EROFS           Read-only filesystem (POSIX.1)

       ESHUTDOWN       Cannot send after transport endpoint shutdown

       ESPIPE          Invalid seek (POSIX.1)

       ESOCKTNOSUPPORT Socket type not supported

       ESRCH           No such process (POSIX.1)

       ESTALE          Stale file handle (POSIX.1)

                       This error can occur for NFS and for other filesystems

       ESTRPIPE        Streams pipe error

       ETIME           Timer expired (POSIX.1 (XSI STREAMS option))

                       (POSIX.1 says "STREAM ioctl(2) timeout")

       ETIMEDOUT       Connection timed out (POSIX.1)

       ETXTBSY         Text file busy (POSIX.1)

       EUCLEAN         Structure needs cleaning

       EUNATCH         Protocol driver not attached

       EUSERS          Too many users

       EWOULDBLOCK     Operation would block (may be same value as EAGAIN) (POSIX.1)

       EXDEV           Improper link (POSIX.1)

       EXFULL          Exchange full

linux支持多线程存取errno,定义为:

extern int *__errno_location(void);
#define errno (*__errno_location())

errno两条规则:
如果没有出错,其值不会被例程清除,仅当函数的返回值指明出错时,才检验其值。
任何函数都不会将errno设置为0。

C标准定义了两个函数,用于打印出错信息。

#include 
char *strerror(int errnum);

strerror函数将errnum(通常就是errno值)映射为一个出错消息字符串,并且返回此字符串的指针。
perror函数基于errno的当前值,在错误标准上产生一条出错信息,然后返回

#include 
void perror(const char *msg);
#include "apue.h"
#include 

int
main(int argc, char *argv[])
{
    fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
    errno = ENOENT;
    perror(argv[0]);
    exit(0);
}

编译执行:

./testerror 
EACCES: Permission denied
./testerror: No such file or directory

我们将argv[0]作为perror参数,让程序名作为错误信息一部分来输出,是一种Unix编程惯例,我们经常可以看到,当程序运行失败的时候,会出现失败程序的名称,这样就能很方便的分清出错程序是哪一个。

用户标识

用户id(uid)是一个数值,它向系统标识不同的用户,uid为0的用户即为root用户,它能对系统为所欲为,在查看很多GNU软件的源代码的时候,我们经常可以看到这样的代码

if (getuid() == 0)

也就是说一个进程拥有root权限,那么大部分文件权限检查都不再执行。
组id(gid)是一个数值,用于确定用户所属用户组。这种机制能够让同组内的不同成员共享资源,系统维护了一个uid、gid与用户名、组名映射对应的机制,一般情况下就是/etc/passwd和/etc/group文件,目前大部分的Unix系统使用32位整形表示uid和gid,我们可以通过检查uid_t和gid_t来确定。

#include "apue.h"

int
main(void)
{
    printf("uid = %d, gid = %d\n", getuid(), getgid());
    exit(0);
}

每个用户除了在/etc/passwd中指定了一个gid以外,大多数Unix版本还允许一个用户属于其他一些组,POSIX标准要求系统应该最少支持8个附属组,但是实际上大多数系统都支持至少16个附属组。
注:Mac OS X系统并非依靠/etc/passwd来维护用户列表,这个文件只有系统以单用户模式启动的时候才会使用

信号

信号用于通知进程发生了某些情况。例如一个进程执行了除以0的操作,CPU引发中断,内核截获中断,然后发出SIGFPE(浮点异常)信号给进程,进程有三种方式处理信号:

1.忽略信号。由于很多信号表示硬件异常,例如,除以0或者访问进程地址空间以外的存储单元,因为这些异常引起的后果不明确,所以不推荐使用这种方式。
2.系统默认方式处理。对于很多信号,系统默认方式就是终止进程,这点非常类似现代编程语言中异常的抛出,例如Node.js对于异常不捕获的操作,就是终止进程
3.提供一个函数,信号发生时调用该函数这被称为捕捉该信号。通过提供自编的函数,我们就能知道什么时候产生了信号,并按期望的方式处理它。

很多情况都会产生信号,终端键盘CTRL+C和CTRL+\通常能产生信号终止当前进程,也可以使用kill命令或者kill函数,从当前终端或者进程向另外一个进程发送一个信号,当然,想要发送一个信号,我们必须是接受信号的进程的所有者或者root用户。

时间值

历史上,UNIX系统使用过两种不同的时间值。
(1)日历时间。该值是自协调世界时(UTC) 1970年1月1日00:00:00这个特定时间以来所经过的秒数累计值。这个时间值可用于记录文件最近一次的修改时间等。
系统基本数据类型time_t用于保存这种时间值。
(2)进程时间。也被称为CPU时间,用以度量进程使用的中央资源处理器资源。进程时间以时钟滴答计算。每秒钟曾经取为50、60或100个时钟滴答。
系统基本数据类型clock_t保存这种时间值
Unix系统为一个进程维护了三个进程时间值

时钟时间
用户CPU时间
系统CPU时间

时钟时间也称为真实事件,是进程运行的时间总量,用户CPU时间是执行用户指令所用的时间量,系统CPU时间是指执行内核指令所用的时间量,用户CPU时间与系统CPU时间之和就是CPU时间。

cd /usr/include/
time -p grep _POSIX_SOURCE */*.h > /dev/null
real 1.65
user 0.01
sys 0.02

某些shell并不运行/usr/bin/time程序,而是使用内置函数测量

系统调用与库函数

系统调用与库函数之间有根本的区别,我们可以替换库函数,但是系统调用通常是不能被替换的。
例如内存管理malloc函数族,它是一种通用存储器管理器,它自己的描述是这样的

The malloc(), calloc(), valloc(), realloc(), and reallocf() functions allocate memory.  The allocated memory is aligned such that it can
be used for any data type, including AltiVec- and SSE-related types.  The free() function frees allocations that were created via the
preceding allocation functions.

而Unix系统内部的分配内存的系统调用是sbrk和’brk’,它们并不分配变量内存,它们只是根据字节数改变segment size,正如系统手册上写的

The brk and sbrk functions are historical curiosities left over from earlier days before the advent of virtual memory management.  The
brk() function sets the break or lowest address of a process's data segment (uninitialized data) to addr (immediately above bss).  Data
addressing is restricted between addr and the lowest stack pointer to the stack segment.  Memory is allocated by brk in page size pieces;
if addr is not evenly divisible by the system page size, it is increased to the next page boundary.

malloc只是实现了类型内存分配,但是分配内存用的还是sbrk系统调用,如果有兴趣,我们完全可以自行实现内存的分配,但是我们不可能越过系统调用。换言之,系统调用分配了空间,而malloc只是在用户层次管理分配的内存空间。

你可能感兴趣的:(apue学习笔记)