├── .gitignore ├── README.md ├── SUMMARY.md └── docs ├── .gitignore ├── AIO.md ├── ANSI_IO.md ├── Home.md ├── IO复用.md ├── POSIX信号量.md ├── README.md ├── XSI-IPC.md ├── accept.md ├── basename.md ├── bind.md ├── book.json ├── chown.md ├── connect.md ├── difftime.md ├── dup.md ├── epoll.md ├── epoll_create.md ├── epoll_ctl.md ├── epoll_wait.md ├── errno.md ├── exec.md ├── fclose.md ├── fcntl.md ├── feof-ferror.md ├── fopen.md ├── fork.md ├── fprintf-fscanf.md ├── fputc-fgetc.md ├── fputs-fgets.md ├── fseek-rewind.md ├── ftell.md ├── ftok.md ├── fwrite-fread.md ├── getcwd.md ├── getgrgid.md ├── gethostbyname.md ├── getitimer.md ├── getopt.md ├── getpeername.md ├── getpwuid.md ├── getservbyname.md ├── getsockname.md ├── gettimeofday.md ├── kill.md ├── listen.md ├── localtime.md ├── lseek.md ├── mkfifo.md ├── msgctl.md ├── msgget.md ├── msgsnd-msgrcv.md ├── open.md ├── pipe.md ├── poll.md ├── psignal.md ├── pthread_create.md ├── pthread_exit.md ├── pthread_join.md ├── pthread_mutex_init.md ├── pthread_mutexattr_settype.md ├── raise.md ├── read.md ├── recv.md ├── recvfrom.md ├── rename.md ├── select.md ├── sem_open.md ├── semctl.md ├── semget.md ├── semop.md ├── send.md ├── sendto.md ├── shmat-shmdt.md ├── shmctl.md ├── shmget.md ├── shutdown.md ├── sigaction.md ├── signal.md ├── sigprocmask.md ├── sigsuspend.md ├── socket.md ├── socketpair.md ├── sockopt.md ├── stat.md ├── time.md ├── uname.md ├── vfork.md ├── wait.md ├── write.md ├── 主机.md ├── 互斥锁.md ├── 信号处理.md ├── 信号类型.md ├── 信号量.md ├── 信号阻塞.md ├── 值-结果参数.md ├── 共享内存.md ├── 地址转换函数.md ├── 套接字函数.md ├── 套接字结构.md ├── 字节序转换函数.md ├── 带外数据.md ├── 文件I-O.md ├── 文件操作.md ├── 时间.md ├── 服务.md ├── 消息队列.md ├── 目录操作.md ├── 系统管理.md ├── 线程.md ├── 线程同步.md ├── 网络编程.md ├── 进程控制.md └── 进程通信.md /.gitignore: -------------------------------------------------------------------------------- 1 | *_book* 2 | *_book 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Linux API速查手册 2 | ==== 3 | ## https://github.com/guodongxiaren/LinuxAPI/wiki 4 | ### [果冻虾仁](https://www.zhihu.com/people/JellyWong)的Linux系统编程学习记录 5 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | * [首页](docs/Home.md) 2 | * [时间管理](docs/时间.md) 3 | * ANSI 4 | * [time](docs/time.md) 5 | * [difftime](docs/difftime.md) 6 | * [localtime](docs/localtime.md) 7 | * [ctime]() 8 | * POSIX 9 | * [gettimeofday](docs/gettimeofday.md) 10 | * [getitimer/setitimer](docs/gettimeofday.md) 11 | * [系统管理](docs/系统管理.md) 12 | * [uname](docs/uname.md) 13 | * [getpwuid](docs/getpwuid.md) 14 | * [getgrgid](docs/getgrgid.md) 15 | * [命令行]() 16 | * [getopt](docs/getopt.md) 17 | * [文件IO](docs/文件IO.md) 18 | * [ANSI]() 19 | * [fwrite](docs/fwrite-fread.md) 20 | * [fread](docs/fwrite-fread.md) 21 | * [fputs](docs/fputs-fgets.md) 22 | * [fgets](docs/fputs-fgets.md) 23 | * [feof](docs/feof-ferror.md) 24 | * [ferror](docs/feof-ferror.md) 25 | * [fseek](docs/fseek-rewind.md) 26 | * [rewind](docs/fseek-rewind.md) 27 | * [ftell](docs/ftell.md) 28 | * [fopen](docs/fopen.md) 29 | * [fclose](docs/fclose.md) 30 | * [POSIX]() 31 | * [open](docs/open.md) 32 | * [read](docs/read.md) 33 | * [write](docs/write.md) 34 | * [lseek](docs/lseek.md) 35 | * [fcntl](docs/fcntl.md) 36 | * [dup](docs/dup.md) 37 | * [文件操作](docs/文件操作.md) 38 | * [chown](docs/chown.md) 39 | * [rename](docs/rename.md) 40 | * [stat](docs/stat.md) 41 | * [dirname](docs/basename.md) 42 | * [basename](docs/basename.md) 43 | * [目录操作](docs/目录操作.md) 44 | * [getcwd](docs/getcwd.md) 45 | * [进程控制](docs/进程控制.md) 46 | * [fork](docs/fork.md) 47 | * [vfork](docs/vfork.md) 48 | * [exec~](docs/exec.md) 49 | * [system]() 50 | * [wait](docs/wait.md) 51 | * [waitpid]() 52 | * [进程通信](docs/进程通信.md) 53 | * [管道]() 54 | * [pipe](docs/pipe.md) 55 | * [mkfifo](docs/mkfifo.md) 56 | * [信号处理](docs/信号处理.md) 57 | * [信号类型](docs/信号类型.md) 58 | * [psignal](docs/psignal.md) 59 | * [kill](docs/kill.md) 60 | * [raise](docs/raise.md) 61 | * [signal](docs/signal.md) 62 | * [sigaction](docs/sigaction.md) 63 | * [信号阻塞](docs/信号阻塞.md) 64 | * [sigsuspend](docs/sigsuspend.md) 65 | * [sigalstack]() 66 | * [IPC对象/XSI-IPC](docs/XSI-IPC.md) 67 | * [消息队列](docs/消息队列.md) 68 | * [msgget](docs/msgget.md) 69 | * [msgctl](docs/msgctl.md) 70 | * [msgsnd](docs/msgsnd-msgrcv.md) 71 | * [msgrcv](docs/msgsnd-msgrcv.md) 72 | * [信号量](docs/信号量.md) 73 | * [semget](docs/semget.md) 74 | * [semctl](docs/semctl.md) 75 | * [semop](docs/semop.md) 76 | * [共享内存](docs/共享内存.md) 77 | * [shmget](docs/shmget.md) 78 | * [shmctl](docs/shmctl.md) 79 | * [shmat](docs/shmat-shmdt.md) 80 | * [shmdt](docs/shmat-shmdt.md) 81 | * [IPC对象/POSIX]() 82 | - [消息队列]() 83 | - [信号量](docs/POSIX信号量.md) 84 | - [共享内存]() 85 | * [网络编程](docs/网络编程.md) 86 | * [套接字结构](docs/套接字结构.md) 87 | * [套接字函数](docs/套接字函数.md) 88 | * [字节序转换](docs/字节序转换函数.md) 89 | * [地址转换](docs/地址转换函数.md) 90 | * [主机](docs/主机.md) 91 | * [服务](docs/服务.md) 92 | * [带外数据](docs/带外数据.md) 93 | * [sockatmark]() 94 | * [线程](docs/线程.md) 95 | - 基本编程 96 | * [pthread_create](docs/pthread_create.md) 97 | * [pthread_exit](docs/pthread_exit.md) 98 | * [pthread_join](docs/pthread_join.md) 99 | - [线程同步](docs/线程同步.md) 100 | - [互斥锁](docs/互斥锁.md) 101 | - [条件变量]() 102 | - [读写锁]() 103 | - [线程信号]() 104 | - [POSIX信号量](docs/POSIX信号量.md) 105 | * [I/O复用](docs/IO复用.md) 106 | - [select](docs/select.md) BSD 107 | - [poll](docs/poll.md) System V 108 | - [epoll模型](docs/epoll.md) 109 | * [epoll_create](docs/epoll_create.md) 110 | * [epoll_ctl](docs/epoll_ctl.md) 111 | * [epoll_wait](docs/epoll_wait.md) 112 | * [异步IO(AIO)](docs/AIO.md) 113 | 114 | 115 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _book 2 | -------------------------------------------------------------------------------- /docs/AIO.md: -------------------------------------------------------------------------------- 1 | Linux 异步IO 2 | >编译时链接实时库,使用选项 `-lrt` 3 | 4 | ##aiocbstruct 5 | aiocb是"asynchronous I/O control block"的缩写。 6 | ```c 7 | struct aiocb { 8 | /* The order of these fields is implementation-dependent */ 9 | 10 | int aio_fildes; /* File descriptor */ 11 | off_t aio_offset; /* File offset */ 12 | volatile void *aio_buf; /* Location of buffer */ 13 | size_t aio_nbytes; /* Length of transfer */ 14 | int aio_reqprio; /* Request priority */ 15 | struct sigevent aio_sigevent; /* Notification method */ 16 | int aio_lio_opcode; /* Operation to be performed; 17 | lio_listio() only */ 18 | 19 | /* Various implementation-internal fields not shown */ 20 | }; 21 | 22 | /* aio_lio_opcode: */ 23 | enum { LIO_READ, LIO_WRITE, LIO_NOP }; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/ANSI_IO.md: -------------------------------------------------------------------------------- 1 | ##文件数据格式 2 | 分为: 3 | * ASCII文件(文本文件,字符文件) 4 | * 二进制文件 5 | 6 | 区别: 7 | 比如一个数字-1000,在文本文件中分别存储五个字符的二进制码。而在二进制文件中直接存储该数字的二进制值。 8 | 文本文件更直观(可以直接用cat命令查看,或用任何编辑器打开观看),但二进制文件更节约存储空间。 9 | ##FILE文件指针 10 | ```c 11 | //在/usr/inclue/stdio.h中 12 | typedef _IO_FILE FILE; 13 | //在/usr/inclue/libio.h中 14 | struct _IO_FILE{ 15 | char* _IO_read_ptr; /* Current read pointer */ 16 | char* _IO_read_end; /* End of get area. */ 17 | char* _IO_read_base; /* Start of putback+get area. */ 18 | char* _IO_write_base; /* Start of put area. */ 19 | char* _IO_write_ptr; /* Current put pointer. */ 20 | char* _IO_write_end; /* End of put area. */ 21 | char* _IO_buf_base; /* Start of reserve area. */ 22 | char* _IO_buf_end; /* End of reserve area. * 23 | ... 24 | int _filene; /*文件描述符*/ 25 | }; 26 | ``` 27 | ##注意事项 28 | 文件操作结束后,都应该: 29 | * 关闭打开的文件,fclose(fp); 30 | * 文件指针置空,fp=NULL; 31 | -------------------------------------------------------------------------------- /docs/Home.md: -------------------------------------------------------------------------------- 1 | Linux环境编程API 2 | =========== 3 | 4 | ##内容概要 5 | C语言API包含*部分*标准C的API、POSIX标准的系统编程API(一些Linux独有的系统API会单独注明)。 6 | ##头文件源码 7 | 大部分头文件源码在**/usr/include**目录下。 8 | ##安装man手册 9 | 因为涉及到大量的POSIX编程。所以最好下载POSIX函数的man手册。 10 | ###Ubuntu 11 | ``` 12 | sudo apt-get install manpages-posix 13 | sudo apt-get install manpages-posix-dev 14 | ``` 15 | 默认安装了**manpages-dev**,所以不装POSIX的man手册是可以查看绝大部分API的。 16 | 但是不装的话,有些API是不能看到的,比如**posix_spawn**函数。 17 | ###CentOS 18 | ``` 19 | yum install man-pages.noarch 20 | ``` 21 | 22 | --------- 23 | >关于目录 24 | >>右侧的目录并非以**函数**为索引依据,主要是以系统的man手册页面为索引依据。 25 | 比如[exec](./exec)里面包含6个函数、[pipe](./pipe)里面包含pipe()和pipe2()两个函数,但是它们都是属于一个man页面中。 -------------------------------------------------------------------------------- /docs/IO复用.md: -------------------------------------------------------------------------------- 1 | I/O多路复用常用于I/O操作可能会被阻塞的情况 2 | - select()出自BSD系统,poll()出自 System V系统。两者原理等价,实现方式不同。POSIX.1定义了两者。 3 | - epoll()出自Linux2.6,其他Unix系统无此函数,BSD系统(包括OSX系统)有类似的函数kequeue() -------------------------------------------------------------------------------- /docs/POSIX信号量.md: -------------------------------------------------------------------------------- 1 | ##头文件 2 | - semaphore.h 3 | - sys/stat.h 4 | - fcntl.h 5 | 6 | ##常用函数 7 | |函数|说明 8 | |---|--- 9 | |[[sem_open|sem_open]]|打开一个有名信号量 10 | |[[sem_close|sem_close]]|关闭一个信号量 11 | |[[sem_unlink|sem_unlink]]|删除一个信号量 12 | |[[sem_post|sem_post]]|【V操作】释放操作:信号量的值加1 13 | |[[sem_wait|sem_wait]]|【P操作】分配操作:信号量的值减1 14 | |[[sem_getvalue|sem_getvalue]]|获取信号量的值 15 | |[[sem_init|sem_init]]|初始化一个无名信号量 16 | |[[sem_destroy|sem_destroy]]|破坏一个无名信号量 -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Linux API速查手册 2 | ==== 3 | ###[果冻虾仁](http://guodongxiaren.me)的Linux系统编程学习记录 4 | 5 |
6 | 7 |
8 | -------------------------------------------------------------------------------- /docs/XSI-IPC.md: -------------------------------------------------------------------------------- 1 | 因为最早出自System V系统中,故又称System V IPC。 2 | 分为: 3 | * 消息队列 4 | * 信号量 5 | * 共享内存 6 | 7 | 这个三种通信方式共用了许多概念。都用到一个头文件**ipc.h**。 8 | >ipc.h位于/usr/include/linux/ipc.h 9 | 10 | ##IPC结构 11 | ```c 12 | struct ipc_perm { 13 | key_t __key; /* Key supplied to semget(2) */ 14 | uid_t uid; /* Effective UID of owner */ 15 | gid_t gid; /* Effective GID of owner */ 16 | uid_t cuid; /* Effective UID of creator */ 17 | gid_t cgid; /* Effective GID of creator */ 18 | unsigned short mode; /* 权限 */ 19 | unsigned short __seq; /* Sequence number */ 20 | }; 21 | ``` 22 | 权限mode字段,对于IPC结构而言,都没有执行的权限。 23 | 消息队列和共享内存使用术语读(read)和写(write),而信号量使用术语读(read)和更改(alter)。 24 | >结构限制 25 | 每种结构都有内置的限制。Linux可以用`ipcs -l`命令查看 26 | 27 | ##函数 28 | ###公共函数 29 | * [ftok](ftok) 30 | 31 | ###其他函数 32 | |分类|创建函数|控制函数|独立函数 33 | |-----|:---:|:-----:|:-----: 34 | |消息队列|[[msgget|msgget]]|[[msgctl|msgctl]]|[msgsnd/msgrcv](msgsnd-msgrcv) 35 | |信号量|[[semget|semget]]|[[semctl|semctl]]|[semop](semop) 36 | |共享内存|[[shmget|shmget]]|[[shmctl|shmctl]]|[shmat/shmdt](shmat-shmdt) 37 | 38 | ###操作 39 | 三个函数中都会使用一个**操作**参数。有四个操作是公共操作,定义在ipc.h中。 40 | 下面**以消息队列举例子**讲解这四个公共操作: 41 | ####IPC_RMID 42 | 删除消息队列。从系统中删除给消息队列以及仍在该队列上的所有数据,这种删除立即生效。 43 | 仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错,并返回EIDRM。 此命令只能由如下两种进程执行: 44 | 其有效用户ID等于msg_perm.cuid或msg_perm.guid的进程。 45 | 另一种是具有超级用户特权的进程。 46 | ####IPC_SET 47 | 设置消息队列的属性。按照buf指向的结构中的值,来设置此队列的msqid_id结构。 48 | 该命令的执行特权与上一个相同。 49 | ####IPC_STAT 50 | 读取消息队列的属性。取得此队列的msqid_ds结构,并存放在buf*中。 51 | ####IPC_INFO 52 | 读取消息队列基本情况。 53 | -------------------------------------------------------------------------------- /docs/accept.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | int accept(int socket, struct sockaddr *cliaddr, socklen_t *addrlen); 7 | ``` 8 | ##描述 9 | accept()用于接收子服务套接字socket上的连接请求。在有客户进程企图与socket连接时,它创建一个新套接字与这个客户通信,并返回新套接字的描数字。新套接字与套接字socket的类型和通信域均相同。原来的套接字socket仍保持打开并且是未连接的,它可用来再次调用accept()接收另外的连接直到关闭为止。 10 | ##参数 11 | - cliaddr是出参(结果参数),返回客户端套接字的协议地址,可以置为NULL。 12 | - addrlen是值-结果参数,必须被初始化为cliaddr所指定地址的字节数,返回其实际占用的字节数 -------------------------------------------------------------------------------- /docs/basename.md: -------------------------------------------------------------------------------- 1 | **basename()和dirname()是一对。** 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | char *dirname(char *path); 7 | 8 | char *basename(char *path); 9 | ``` 10 | ##功能比较 11 | path | dirname| basename 12 | |----|----|---- 13 | /usr/lib| /usr| lib 14 | /usr/ | / | usr 15 | usr | . | usr 16 | / | / | / 17 | . | . | . 18 | .. | . | .. 19 | 20 | 也可以用于**url**。 -------------------------------------------------------------------------------- /docs/bind.md: -------------------------------------------------------------------------------- 1 | bind函数用于给套接字命名。所谓命名指的是给一个协议地址赋予一个套接字。只有命名的套接字才能被其他进程找到。通常只有提供对外服务的套接字需要bind(),客户端无需bind()。 2 | 3 | 服务端程序在调用bind()命名地址之后执行两个步骤:listent()和accept() 4 | ##函数原型 5 | ```c 6 | #include 7 | #include 8 | 9 | int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen); 10 | ``` 11 | ##参数 12 | - sockfd是套接字描数字 13 | - myddr是套接字地址结构指针,一般由sockddr_in或sockaddr_in6转型。 14 | - addrlen是套接字地址结构的sizeof值 15 | 16 | ##返回值 17 | 成功返回0,失败返回-1 18 | ##描述 19 | bind操作涉及三个对象:套接字、地址和端口。其中套接字是捆绑的主体,地址和端口是捆绑的客体。bind可以指定IP地址或端口,可以都指指定,也可以都不指定。 20 | 21 | |IP地址|端口|bind函数执行结果 22 | |-----|----|------------- 23 | |通配地址|0|内核选择IP地址和端口 24 | |通配地址|非0|内核选择IP地址,进程指定端口 25 | |本地IP地址|0|进程指定IP地址,内核选择端口 26 | |本地IP地址|非0|进程指定IP地址或端口 27 | 记忆的方法就是: 28 | - 对于IP地址,若为通配地址([INADDR_ANY](#inaddr_any))则由内核选择IP地址 29 | - 端口为0,则由内核来选择端口。非0则由进程将该非0值设为端口 30 | 31 | ----------- 32 | ##INADDR_ANY 33 | 在头文件``中,定义了一个宏**INADDR_ANY**称作通配名表示地址**0.0.0.0**,系统解释这个地址为程序运行所在机器的任意合法网络地址。 34 | >适用于单主机多IP的情况:假设主机有两个IP,用0来命名的套接字,那么进程可以接收这两个IP地址的连接。 35 | 36 | 尽管**INADDR_ANY**(值为0)的两种字节序是一样的,但因为``中定义的所有**INADDR_**常值,它们都是主机字节序的,所以习惯上依旧要使用[htonl](字节序转换函数)函数进行转换。 -------------------------------------------------------------------------------- /docs/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["toggle-chapters"] 3 | } -------------------------------------------------------------------------------- /docs/chown.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int chown(const char *path, uid_t owner, gid_t group); 6 | int fchown(int fd, uid_t owner, gid_t group); 7 | int lchown(const char *path, uid_t owner, gid_t group); 8 | ``` 9 | 实际执行需要root权限。也就是使用root身份或者sudo来运行该程序的可执行文件。 10 | >If the owner or group is specified as -1, then that ID is not changed. 11 | 12 | ###区别联系 13 | * lchown修改符号链接时,修改的是符号链接权限。 14 | * chown修改符号链接时,修改符号链接指向的文件的权限。 15 | * fchown修改符号连接时,行为和chown相同。只不过它的参数是文件的描述符。 -------------------------------------------------------------------------------- /docs/connect.md: -------------------------------------------------------------------------------- 1 | 客户端函数。属于进程到内核的传递套接字地址结构的函数。 2 | ##函数原型 3 | ```c 4 | #include /* POSIX.1-2001以及Linux都不需要包含此头文件 */ 5 | #include 6 | 7 | int connect(int sockfd, const struct sockaddr *addr, 8 | socklen_t addrlen); 9 | ``` 10 | ##参数 11 | - sockfd必须是套接字描述符 12 | - addr是要连接的远程套接字的地址,依据通信域的不同而不同(使用的时候需要进行类型转换): 13 | 14 | |通信域|addr| 15 | |----|----- 16 | |AF_UNIX|sockaddr_un 17 | |AF_INET|sockaddr_in 18 | |AF_INET6|sockaddr_in6 19 | - addrlen为套接字地址结构的长度,属于**值参数**。POSIX建议socklen_t定义为uint32_t。 20 | 21 | ##返回值 22 | 成功返回0,失败返回-1,并设置errno。可能的错误条件有: 23 | 24 | |errno|描述 25 | |-----|---- 26 | |EBADD|参数socket不是合法的套接字描数字 27 | |EALREADY|已经有一悬挂的连接正在被处理 28 | |ETIMEDOUT|建立连接的时间限已过而未能建立连接 29 | |ECONNREFUSED|服务端拒绝此连接 30 | |EINTR|建立连接的企图被捕获的信号所中断 31 | 32 | 33 | >  正常情况下,当连接不能立即建立时,connect()等待知道服务程序回答了连接请求,或等待时间超过了某个时间限制之后才返回。 34 | 如果是超时返回,**connect()**将失败并且流产(abort)连接请求。如果**connert()**在阻塞期间由于收到信号而被中断,它将失败并置**errno**为**EINTER**,但是连接请求不会流产,而是异步地被建立。 35 |   可以对套接字socket设置非阻塞方式,从而使connect()不等待回答就直接返回。对套接字设置非阻塞方式的方法同文件描述字一样使用fcntl()。 36 |   如果对套接字socket设置了非阻塞标志**O_NONBLOCK**,当连接不能立即建立时,**connect()**将失败并置errno为**EINPROGRESS**,但是连接请求不会被流产而是被异步地建立。在连接建立之前,后继对同一套接字调用connect()将导致EALREADY而失败。 37 |   对于异步建立的连接,可用**select()**和**poll()**来指出套接字就绪。 38 |   客户进程调用**connect()**之前不必调用**bind()**,内核在必要时会为该套接字选择适当的地址。 39 | >>引用自《Unix/Linux程序设计教程》(赵克佳、沈志宇编)P380 -------------------------------------------------------------------------------- /docs/difftime.md: -------------------------------------------------------------------------------- 1 | 计算两个时间的差值 2 | 3 | 一般人们会用两次time()的结果直接相减来获取差值,但是time_t的类型ANSI C并未规定,有的系统是整型有的系统是浮点型或其他编码。为了兼容性,ANSI C的difftime()统一返回双精度浮点数。 4 | ##函数原型 5 | ```c 6 | #include 7 | 8 | double difftime(time_t time1, time_t time0); 9 | ``` 10 | ##备注 11 | 实际上在POSIX系统中,常被定义成: 12 | ```c 13 | #define difftime(t1,t0) (double)(t1 - t0) 14 | ``` -------------------------------------------------------------------------------- /docs/dup.md: -------------------------------------------------------------------------------- 1 | 复制文件描述符号 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int dup(int oldfd); 7 | int dup2(int oldfd, int newfd); 8 | 9 | ``` 10 | 另外还有dup3(),不常用。 11 | 12 | ##dup,dup2 13 | - dup参数是一个文件描述符,返回一个文件描述符,值是当前未使用的最小数字,指向的位置和参数相同。 14 | - dup2,可以自己指定要返回的文件描述的数值newfd,如果newfd是一个已经打开的文件描述符,则会将其关闭。 15 | 16 | ##dup2,fcntl 17 | ```c 18 | dup2(fd,fd2); 19 | //等价于 20 | close(fd2); 21 | fcntl(fd,F_DUPFD,fd2); 22 | ``` 23 | 功能上可以等价于close()和fcntl()的组合,但是dup2是一个原子操作(关闭fd2,和复制fd不会被中断)。 -------------------------------------------------------------------------------- /docs/epoll.md: -------------------------------------------------------------------------------- 1 | ##主要函数 2 | |函数|描述 3 | |----|---- 4 | |[[epoll_create|epoll_create]]|创建一个epoll的文件描述符 5 | |[[epoll_ctl|epoll_ctl]]|epoll的事件注册函数 6 | |[[epoll_wait|epoll_wait]]|收集在epoll监控的事件中已经发送的事件 7 | 8 | ##结构体 9 | ###epoll_event 10 | ```c 11 | typedef union epoll_data { 12 | void *ptr; 13 | int fd; 14 | uint32_t u32; 15 | uint64_t u64; 16 | } epoll_data_t; 17 | 18 | struct epoll_event { 19 | __uint32_t events; /* Epoll events */ 20 | epoll_data_t data; /* User data variable */ 21 | }; 22 | ``` 23 | ##HINT 24 | epoll_create生成的epfd,是内核中epoll结构的唯一标识。**epoll结构不直接面向应用程序员**。它维持着每个epoll处理要监视的fd及其感兴趣事件。要修改它只能通过epoll_ctl。 -------------------------------------------------------------------------------- /docs/epoll_create.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int epoll_create(int size); 6 | 7 | ``` 8 | ##参数 9 | size参数自从Linux 2.6以后被忽略了。 10 | 11 | -------------------------------------- 12 | >epoll_create1 13 | 14 | ```c 15 | #include 16 | int epoll_create1(int flags); 17 | ``` -------------------------------------------------------------------------------- /docs/epoll_ctl.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 6 | ``` 7 | ##参数 8 | ###epfd 9 | 是[[epoll_create|epoll_create]]的返回值。 10 | ###op 11 | 表示动作,它由三个宏来表示 12 | - EPOLL_CTL_ADD:注册新的fd到epfd中; 13 | - EPOLL_CTL_MOD:修改已经注册的fd的监听事件; 14 | - EPOLL_CTL_DEL:从epfd中删除一个fd; 15 | 16 | ###fd 17 | 要监听的文件描述符 18 | ###event 19 | 可以是以下几个宏`逻辑或`的组合 20 | 21 | |宏|描述 22 | |---|---- 23 | EPOLL**IN** |表示对应的文件描述符可以读(包括对端SOCKET正常关闭) 24 | EPOLL**OUT**|表示对应的文件描述符可以写 25 | EPOLL**PRI**|表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来) 26 | EPOLL**ERR**|表示对应的文件描述符发生错误 27 | EPOLL**HUP**|表示对应的文件描述符被挂断 28 | EPOLL**ET**| 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的 29 | EPOLL**ONESHOT**|只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里 30 | 31 | 检测event(struct epoll_event类型)是否包含某一标识 32 | ```c 33 | if(event & EPOLLHUP){ 34 | ... 35 | } 36 | if(event & (EPOLLPRI|EPOLLERR|EPOLLHUP)){ 37 | ... 38 | } 39 | ``` -------------------------------------------------------------------------------- /docs/epoll_wait.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int epoll_wait(int epfd, struct epoll_event *events, 6 | int maxevents, int timeout); 7 | ``` 8 | ##参数 9 | ###events 10 | 出参,记录准备好的fd。该参数为向量(数组),由调用方分配空间。 11 | ###maxevents 12 | 最大监听**fd**。epoll_wait会检测从0到maxevents的所有fd是否就绪,如果就绪就保存到events中。 13 | ###timeout 14 | - 0,不阻塞立即返回 15 | - -1,阻塞直到监听的一个fd上有一个感兴趣事件发生 16 | - >0,阻塞指定时间。直到监听的fd上有感兴趣事件发生,或者捕捉到信号 17 | 18 | ##返回值 19 | - >0,返回准备好的fd数量 20 | - 0,超时 21 | - -1,出错 22 | 23 | 通常遍历events[0]~events[返回值-1]的元素。这些都是就绪的。并且保存了就绪的事件。 24 | >events下标与fd并不相同 -------------------------------------------------------------------------------- /docs/errno.md: -------------------------------------------------------------------------------- 1 | 错误 2 | ---- 3 | ###errno 4 | 在头文件**error.h**中定义。在函数调用出错的时候会设置相应的errno的值。 5 | - [x] 注意 6 | * 如果系统调用或库函数正确执行的话,errno的值是不会被置0。 7 | * 系统调用或库函数正确执行,并不保证errno的值不会被改变! 8 | * 任一函数都不会将errno值置0。 9 | * 任何错误号(即发生错误时errno的取值)都是非0的。 10 | 11 | ###perror 12 | 头文件**stdio.h** 13 | 打印错误信息。打印出来就是**stderr**。 14 | ###strerror 15 | 将error翻译成具体错误信息。实际使用时需要包含: 16 | ```c 17 | #include 18 | #include 19 | ``` 20 | 两个头文件。 -------------------------------------------------------------------------------- /docs/exec.md: -------------------------------------------------------------------------------- 1 | exec函数族的作用是让fork出的子进程能够执行与父进程不同的代码段,实现不同的功能。 2 | ###exec由6个函数组成 3 | ```c 4 | int execl(const char *path,const char *arg,...); 5 | int execlp(const char *file,const char *arg,...); 6 | int execle(const char *path,const char *arg,...,char *const encp[]); 7 | 8 | int execv(const char *path,const char *argv[]); 9 | int execvp(const char *file,const char *argv[]); 10 | int execve(const char *path,const char *argv[],char *const envp[]); 11 | ``` 12 | ###如何记忆 13 | |字符|原型|描述| 14 | |---|---|---| 15 | |l|list|选项列表,对应函数的省略号,可以写多个参数,以NULL结尾| 16 | |v|vector|将命令的多个选项放到一个数组里,作为第二个参数| 17 | |p|path|在系统PATH变量的路径里搜索,无p字符的函数则需要给出可执行文件的全路径名| 18 | |e|enviroment|表示将一份新的环境变量传给他?| 19 | 20 | ###样例 21 | ```c 22 | execlp("ls", "ls", "-a", (char *)NULL); 23 | char *v[] = {"ls", "-a", NULL}; 24 | execvp("ls", v); 25 | ``` -------------------------------------------------------------------------------- /docs/fclose.md: -------------------------------------------------------------------------------- 1 | 释放文件指针指向的资源,同时使文件描述符失效。 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int fclose(FILE *fp); 7 | ``` 8 | ##参数 9 | 参数为文件指针 10 | ##返回值 11 | |返回值|状态| 12 | |:---:|----| 13 | |0|成功| 14 | |EOF|失败| 15 | 失败时会设置适当`errno`的值。 16 | >EOF在stdio.h中定义,值为-1。 -------------------------------------------------------------------------------- /docs/fcntl.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | int fcntl(int fd, int cmd, ... /* arg */ ); 7 | ``` 8 | ##参数 9 | 参数可能有两个,也可能有三个,具体看第二个参数的取值。 10 | - fd: 文件描述符 11 | - cmd: 命令 12 | - arg: 命令的参数 13 | 14 | |常用cmd|arg|描述| 15 | |---|---|--- 16 | |F_DUPFD||复制文件描述符 17 | |F_GETFD|无|获取文件描述符标签 18 | |F_SETFD||设置文件描述符标签 19 | |F_GETFL||获取文件状态标签 20 | |F_SETFL||设置文件状态标签 21 | |F_GETFLK||获取文件锁 22 | |F_SETFLK||设置文件锁 23 | |F_SETLKW||类似**F_SETLK**,但等待完成 24 | |F_GETOWN||获取收到SIGIO信号的进程或进程组ID 25 | |F_SETOWN||设置接收SIGIO信号的进程或进程组ID 26 | 27 | ##文件描述符标签 28 | - 文件描述符标签(flags)是一个整型,它的每一个二进制为,表明一种标志。 29 | - 复制的文件描述符,标签不会被复制,每个文件描述符有各自的标签 30 | 31 | 当前,只有一个标志**FD_CLOEXEC**,表明当执行exec()函数时,将关闭该文件描述符。默认情况下,此位是清除的,所以在执行exec()之后,之前的文件描述符会保留。 32 | ```c 33 | fcntf(fd,F_SETFD,FD_CLOEXEC);//设置该标志,但是其他标志就消失了。 34 | //良好的写法是: 35 | int oldflags = fcntl(fd,F_GETFD); 36 | oldflags |= FD_CLOEXEC;//设置该标志 37 | fcntl(fd,F_SETFD,oldflags); 38 | 39 | //如果要清除该标志 40 | oldflags &= ~FD_CLOEXEC; 41 | ``` 42 | ##文件状态标签 43 | 文件状态标签被所有复制的文件描述符共享。表明文件打开的属性,也就是open()的flags参数所指明的。 44 | 当判断一个文件的读写标志时,不能简单的通过**&**操作来判断,因为文件的读写标志有三种状态,系统中并非设置了三个独立位来表示,实际上是用了两个位来表示的。所以最好使用**O_ACCMODE**(0x3)来进行**&**操作。 45 | 其他的标志可以直接用**&**来判断,如`flags&O_APPEND` 46 | -------------------------------------------------------------------------------- /docs/feof-ferror.md: -------------------------------------------------------------------------------- 1 | feof/ferror 2 | ----- 3 | ###函数原型 4 | ```c 5 | int feof(FILE *fp); 6 | int ferror(FILE *fp); 7 | ``` 8 | ###功能描述 9 | ####feof 10 | 测试fp指向的流是否设置了EOF标记(end-of-file indicator)。 11 | 即是否到达文件结尾。 12 | 该标记只能被clearerr函数清除。 13 | 若fp当前位置是文件结尾,则返回非0值,否则返回0。 14 | ####ferror 15 | 测试fp指向的流是否设置了错误标记(error indicator)。 16 | 是否到达文件结尾。 17 | 该标记只能被clearerr函数清除。 18 | 若该标记被设置,则返回非0值。即表示出错。 19 | ###示例 20 | ```c 21 | ... 22 | while(!feof(fp)) 23 | { 24 | ... 25 | } 26 | ``` 27 | 若不是文件结尾则执行循环。 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/fopen.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | FILE *fopen(const char *path, const char *mode); 6 | FILE *fdopen(int fd, const char *mode); 7 | FILE *freopen(const char *path, const char *mode, FILE *stream); 8 | ``` 9 | **`fopen`** 10 | ##参数 11 | * path 要打开的文件路径名 12 | * mode 文件的打开方式,6种取值 13 | 14 | ###mode 15 | |字符|描述| 16 | |:--|---- 17 | |r|只读,文件必须已存在 18 | |r+|允许读写,文件必须已存在 19 | |w|只写,文件不存在在创建,已存在则覆盖原内容写入 20 | |w+|允许读写,文件不存在在创建,已存在则覆盖原内容写入 21 | |a|只允许追加数据,文件不存在则创建 22 | |a+|允许读和追加数据,文件不存在则创建 23 | ##返回值 24 | 如果调用成功,返回**文件指针**;否则返回**NULL**并设置适当的`errno`信息。 -------------------------------------------------------------------------------- /docs/fork.md: -------------------------------------------------------------------------------- 1 | 从父进程派生出子进程,子进程完全拷贝父进程的stack,data,heap segment。 2 | >两者并不共享地址空间,所以的变量是独立的,一方修改,另一方不会变化。 3 | 4 | ###函数原型 5 | ```c 6 | #include 7 | 8 | pid_t fork(void); 9 | ``` 10 | ###特点 11 | 一次调用,两次返回 12 | -------------------------------------------------------------------------------- /docs/fprintf-fscanf.md: -------------------------------------------------------------------------------- 1 | fprintf/fscanf 2 | ----------------- 3 | 和printf与scanf及其类似。唯一的不同之处是print/scanf是面向标准输出/输入的。 4 | 而fprintf/fscanf则是面向FILE指针。当然stdout/stdin 也是FILE指针。 5 | ###函数原型 6 | ```c 7 | #include 8 | 9 | int fprintf(FILE *fp,const char *format,...); 10 | int fscanf(FILE *fp,const char *format,...); 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/fputc-fgetc.md: -------------------------------------------------------------------------------- 1 | fputc 2 | ---- 3 | 向文件中写入字符 4 | ###格式 5 | fputc(ch,fp); 6 | ###返回值 7 | 返回刚写入到文件中的字符,若出现错误则返回EOF。 8 | ###示例 9 | ```c 10 | ... 11 | for(i=0;i<10;i++) 12 | { 13 | ch=getchar(); 14 | fputc(ch,fp); 15 | } 16 | ``` 17 | fgetc 18 | ----- 19 | 从文件读取单个字符 20 | ###格式 21 | ch=fgetc(fp); 22 | ###返回值 23 | 返回读到的字符,并转型成int。若到文件结尾返回EOF 24 | ###示例 25 | ```c 26 | ... 27 | for(i=0;i<10;i++) 28 | { 29 | ch=fgetc(fp); 30 | putchar(ch); 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/fputs-fgets.md: -------------------------------------------------------------------------------- 1 | fputs 2 | ----- 3 | 写入字符串到文件 4 | ###函数原型 5 | ```c 6 | #include 7 | int fputs(const char *s,FILE *fp); 8 | ``` 9 | ###功能描述 10 | 将s指向的字符串,舍去结束标记'\0'后写入到fp指向的文件缓冲区。 11 | ###返回值 12 | 返回写入的实际字符数;出现错误,返回EOF。 13 | 14 | fgets 15 | ----- 16 | 从文件读取字符串 17 | ###函数原型 18 | ```c 19 | char *fgets(char *s,int size,FILE *fp); 20 | ``` 21 | ###功能描述 22 | 从fp所指向的文件缓冲区当前位置读取n-1个字符, 23 | 在其后补充一个'\0',并写入到s指向的内存区。 24 | ###返回值 25 | 返回s对应的地址,可以理解为返回字符串。出现错误返回NULL。 26 | 27 | -------------------------------------------------------------------------------- /docs/fseek-rewind.md: -------------------------------------------------------------------------------- 1 | fseek 2 | ----- 3 | 用于跳跃式地移动文件读写位置。 4 | ###函数原型 5 | ```c 6 | #include 7 | 8 | int fseek(FILE *fp,long offset,int whence); 9 | ``` 10 | ###参数 11 | offset为相较whence的偏移量。 12 | whence为文件内部指针的基准: 13 | * `SEEK_SET` 文件开始位置,其值为0 14 | * `SEEK_CUR` 文件当前位置,其值为1 15 | * `SEEK_END` 文件结束位置,其值为2 16 | 17 | ###返回值 18 | 如果执行成功,将返回0。如果失败返回-1 19 | 20 | rewind 21 | ------- 22 | rewind英文释义是`倒带`的意思。这里是重置文件指针到所指向的文件的开始位置。 23 | ###函数原型 24 | ```c 25 | #include 26 | 27 | void rewind(FILE *fp); 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/ftell.md: -------------------------------------------------------------------------------- 1 | ftell 2 | ------ 3 | tell就是说话的意思,该函数功能为报告当前位置距离文件开始处是第几个字符 4 | ###函数原型 5 | ```c 6 | #include 7 | 8 | long ftell(FILE *fp); 9 | ``` 10 | ###返回值 11 | 返回fp所指向文件流的当前位置。如果出错返回-1 12 | -------------------------------------------------------------------------------- /docs/ftok.md: -------------------------------------------------------------------------------- 1 | ftok函数 2 | ------- 3 | 取file to key之意 4 | ###函数原型 5 | ```c 6 | #include 7 | #include 8 | 9 | key_t ftok(const char *pathname, int proj_id); 10 | ``` 11 | ###参数 12 | pathname必须是存在的,且可访问的文件名(可以包括路径)。 13 | proj_id的低8位会被用到。该参数不能为0。 14 | ###返回值 15 | 返回一个key_t(*int*)类型的key值。 16 | * key的31~24位为ftok第二个参数的低8位。 17 | * key的23~16位为该文件st_dev属性的低8位。 18 | * key的15~0位为该文件st_ino属性的低16位。 -------------------------------------------------------------------------------- /docs/fwrite-fread.md: -------------------------------------------------------------------------------- 1 | ##fwrite 2 | 3 | ###函数原型 4 | ```c 5 | #include 6 | 7 | size_t fwrite(const void *ptr,size_t size,size_t n,FILE *fp); 8 | ``` 9 | ###参数 10 | ptr为基本类型或自定义的结构体类型的指针。 11 | size代表要写入的数据字节数,通常为sizeof(数据类型)。 12 | n代表写入的数据的个数。 13 | fp即为文件指针。 14 | ###返回值 15 | 返回写入的数据的个数。 16 | 如果成功写入则,文件内部指针会向右移动n*size。 17 | 18 | fread 19 | ----- 20 | ###函数原型 21 | ```c 22 | #include 23 | 24 | size_t fread(void *ptr,size_t size,size_t n,FILE *fp); 25 | ``` 26 | ###参数 27 | 与fwrite含义相同。 28 | ###返回值 29 | fread不区分文件结束和错误。如有必要,请使用[feof](feof-ferror)和[ferror](feof-ferror.md)。 30 | -------------------------------------------------------------------------------- /docs/getcwd.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | char *getcwd(char *buf,size_t size); 6 | ``` 7 | ##返回值 8 | 返回当前目录名的绝对路径。 -------------------------------------------------------------------------------- /docs/getgrgid.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | struct group *getgrnam(const char *name); 7 | struct group *getgrgid(gid_t gid); 8 | int getgrnam_r(const char *name, struct group *grp, 9 | char *buf, size_t buflen, struct group **result); 10 | 11 | int getgrgid_r(gid_t gid, struct group *grp, 12 | char *buf, size_t buflen, struct group **result); 13 | ``` 14 | >缩写含义 15 | **getgrnam**--->get group name 16 | **getgruid**--->get group uid 17 | 18 | ##结构体group 19 | 定义在头文件*grp.h*中 20 | ```c 21 | struct group { 22 | char *gr_name; /* 组名 */ 23 | char *gr_passwd; /* 组密码 */ 24 | gid_t gr_gid; /* 组ID */ 25 | char **gr_mem; /* 组成员 */ 26 | }; 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /docs/gethostbyname.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | extern int h_errno; 5 | 6 | struct hostent *gethostbyname(const char *name); 7 | 8 | #include /* for AF_INET *//*貌似不加也可以*/ 9 | struct hostent *gethostbyaddr(const void *addr, 10 | socklen_t len, int type); 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/getitimer.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int getitimer(int which, struct itimerval *curr_value); 6 | int setitimer(int which, const struct itimerval *new_value, 7 | struct itimerval *old_value); 8 | ``` 9 | ##参数 10 | ###which 11 | 指定使用哪一种计时器。Linux 操作系统为每一个进程提供了 3 个内部间隔计时器: 12 | * ITIMER_REAL:减少实际时间.到时的时候发出 SIGALRM 信号。 13 | * ITIMER_VIRTUAL:减少有效时间(进程执行的时间)。产生 SIGVTALRM 信号。 14 | * ITIMER_PROF:减少进程的有效时间和系统时间(为进程调度用的时间)。产生 SIGPROF 信号。 15 | 16 | >后两者经常结合使用用来计算系统内核时间和用户时间 17 | 18 | ###getitimer 19 | 获取当前的计时器。 20 | ###setitimer 21 | 设置新计时器new_value,如果原计时器不为空,则保存到old_value中。 22 | ##结构体itimerval和timeval 23 | ```c 24 | struct itimerval { 25 | struct timeval it_interval; /* 间隔,it_value为0以后会重置为it_interval */ 26 | struct timeval it_value; /* 当前值 */ 27 | }; 28 | 29 | struct timeval { 30 | time_t tv_sec; /* 秒 */ 31 | suseconds_t tv_usec; /* 微秒 */ 32 | }; 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/getopt.md: -------------------------------------------------------------------------------- 1 | 命令行参数识别 2 | ##函数原型 3 | ```c 4 | #include 5 | int getopt(int argc, char * const argv[], 6 | const char *optstring); 7 | 8 | extern char *optarg; 9 | extern int optind, opterr, optopt; 10 | 11 | #include 12 | 13 | int getopt_long(int argc, char * const argv[],const char *optstring, 14 | const struct option *longopts, int *longindex); 15 | 16 | int getopt_long_only(int argc, char * const argv[],const char *optstring, 17 | const struct option *longopts, int *longindex); 18 | ``` 19 | ##参数 20 | getopt的前两个参数无须多言,关键是第三个optstring 21 | * 单个字符,表示选项 22 | * 单个字符后面接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者用空格隔开, 23 | 该参数的指针赋给optarg 24 | * 单个字符后面接两个冒号::表示该选项后可以跟一个参数,且必须紧跟在选项后,不能以空格隔开, 25 | 该参数的指针赋给optarg 26 | 27 | ##返回值 28 | 29 | getopt()成功执行后将返回第一个选项,并设置如下全局变量。 30 | * optarg:指向当前选项的参数(如果有)的指针 31 | * optind:再次调用getopt()时的下一个argv指针的索引 32 | * optopt:存储不可知或错误选项 33 | -------------------------------------------------------------------------------- /docs/getpeername.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 6 | ``` 7 | ##描述 8 | 获取与本地套接字sockfd连接的远程对等套接字的地址。 9 | ##返回值 10 | 成功返回0,失败为-1并设置errno -------------------------------------------------------------------------------- /docs/getpwuid.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | struct passwd *getpwnam(const char *name); 7 | struct passwd *getpwuid(uid_t uid); 8 | 9 | int getpwnam_r(const char *name, struct passwd *pwd, 10 | char *buf, size_t buflen, struct passwd **result); 11 | int getpwuid_r(uid_t uid, struct passwd *pwd, 12 | char *buf, size_t buflen, struct passwd **result); 13 | ``` 14 | >缩写的含义 15 | **getpwnam**--->get password name 16 | **getpwuid**--->get password uid 17 | 18 | ##结构体passwd 19 | 定义在头文件*pwd.h*中 20 | ```c 21 | struct passwd { 22 | char *pw_name; /* 用户名 */ 23 | char *pw_passwd; /* 用户密码 */ 24 | uid_t pw_uid; /* 用户ID */ 25 | gid_t pw_gid; /* 用户组ID */ 26 | char *pw_gecos; /* 用户信息 */ 27 | char *pw_dir; /* home目录 */ 28 | char *pw_shell; /* shell程序 */ 29 | }; 30 | ``` -------------------------------------------------------------------------------- /docs/getservbyname.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | struct servent *getservbyname(const char *name, const char *proto); 6 | ``` 7 | ##描述 8 | 查询服务数据库,匹配服务名为name,使用了proto协议的服务,并返回其servent结构。 9 | ##参数 10 | |参数|类型|描述| 11 | |----|----|----- 12 | |name|const char*|服务名称 13 | |proto|const char*|协议名(tcp或udp),如果该参数为NULL则自动匹配 14 | ##返回值 15 | 错误或读到/etc/services文件结尾则返回NULL,成功返回对应的servent指针 -------------------------------------------------------------------------------- /docs/getsockname.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 6 | ``` 7 | ##描述 8 | 获取本地套接字sockfd的地址(本地可以有多个套接字,所以要指定)。 9 | ##返回值 10 | 成功返回0,出错返回-1并设置errno。 -------------------------------------------------------------------------------- /docs/gettimeofday.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int gettimeofday(struct timeval *tv, struct timezone *tz); 6 | int settimeofday(const struct timeval *tv, const struct timezone *tz); 7 | ``` 8 | ##参数 9 | ###结构体timeval 10 | ```c 11 | struct timeval 12 | { 13 | long tv_sec;/*秒数*/ 14 | long tv_usec;/*微秒数*/ 15 | }; 16 | ``` 17 | 当前时间会返回给这个结构体指针tv。 18 | ###结构体timezone 19 | 可以设为NULL。 20 | ###返回值 21 | - 0 :成功 22 | - -1:失败 -------------------------------------------------------------------------------- /docs/kill.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | int kill(pid_t pid,int sig); 7 | ``` 8 | ##描述 9 | pid|描述| 10 | :-----:|---- 11 | >0|kill发送信号sig给进程pid 12 | 0|kill发送信号给和当前进程在同一进程组的所有进程 13 | -1|信号发送给系统内的所有进程 14 | <-1|kill发送信号sig给进程组-pid中的每个进程 15 | 16 | 17 | ##返回值 18 | * 如果成功完成返回值0 19 | * 失败返回-1,并设置errno -------------------------------------------------------------------------------- /docs/listen.md: -------------------------------------------------------------------------------- 1 | **listen()不允许用于无连接的套接字。** 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int listen(int socket, int backlog); 7 | ``` 8 | listen()为socket建立一个连接请求侦听队列。 9 | ##参数 10 | ###backlog 11 | backlog指明套接字侦听队列未完成连接的数目。通常指定其值大于系统规定的最大值,这时,当侦听队列的连接请求数超过系统的限制值时,系统会自动截断backlog之值为系统最大值。在Linux2.2开始,backlog的含义变成了**已经完成连接**正等待应用程序接收的套接字队列的长度。 12 | 如果backlog小于0,该函数会自动设置侦听队列为0。 13 | ##返回值 14 | 成功返回0,失败返回-1并设置errno错误条件。 15 | -------------------------------------------------------------------------------- /docs/localtime.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | struct tm *localtime(const time_t *timep); 6 | ``` 7 | ##描述 8 | 将参数中timep代表的秒数转换为结构体tm类型。出现错误时返回NULL。 9 | 注意,此时参数timep中的必须是经过time()初始化过的变量。 10 | 所以通常的用法是: 11 | ```c 12 | struct tm* t; 13 | time_t currentTime; 14 | 15 | time(¤tTime); 16 | t = localtime(¤tTime); 17 | ``` 18 | **注意返回的tm的年份是从1900开始计数的,月份是从0开始计数的** 19 | ##tm struct 20 | ```c 21 | struct tm { 22 | int tm_sec; /* Seconds (0-60) */ 23 | int tm_min; /* Minutes (0-59) */ 24 | int tm_hour; /* Hours (0-23) */ 25 | int tm_mday; /* Day of the month (1-31) */ 26 | int tm_mon; /* Month (0-11) */ 27 | int tm_year; /* Year - 1900 */ 28 | int tm_wday; /* Day of the week (0-6, Sunday = 0) */ 29 | int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ 30 | int tm_isdst; /* Daylight saving time */ 31 | }; 32 | ``` -------------------------------------------------------------------------------- /docs/lseek.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | off_t lseek(int fd, off_t offset, int whence); 7 | ``` 8 | ##参数 9 | - fd是文件描述符 10 | - offset是偏移量 11 | - whence是偏移量的基准位置。它的取值有三个 12 | - *SEEK_SET*: 开始位置 13 | - *SEEK_CUR*: 当前位置 14 | - *SEEK_END*: 末尾位置 15 | 16 | >为什么开始位置的后缀是**_SET** 17 | >>实际上,在man手册中可以看出。这三个宏的描述是 18 | - SEEK_SET The offset is set to offset bytes. 19 | - SEEK_CUR The offset is set to its current location plus offset bytes. 20 | - SEEK_END The offset is set to the size of the file plus offset bytes. 21 | 22 | ---------- 23 | ##fd的偏移量 24 | 在内核中对一个文件描述符(fd)的偏移量只维护一个值,也就是说你用读写方式打开一个文件,如果先用read读取了n个字符,紧接着用write写入了n个字符,那么后来写入的n个字符并不是从文件第一个字符位置开始的,而是从n+1个字符位置开始的。所以通常我们需要使用lseek来使fd的偏移量置于文件开始位置。 -------------------------------------------------------------------------------- /docs/mkfifo.md: -------------------------------------------------------------------------------- 1 | 3创建一个命名管道 2 | ##函数原型 3 | ```c 4 | #include 5 | #include 6 | 7 | int mkfifo(const char *pathname, mode_t mode); 8 | ``` 9 | ##参数 10 | 第二个参数的语义与[[open()|open]]的第3个参数相同,即权限。 -------------------------------------------------------------------------------- /docs/msgctl.md: -------------------------------------------------------------------------------- 1 | 该函数用来对消息队列的基本属性进行控制、修改。 2 | ###函数原型 3 | ``` 4 | #include 5 | #include 6 | #include 7 | 8 | int msgctl(int msqid, int cmd, struct msqid_ds *buf); 9 | ``` 10 | ###参数 11 | * msqid为消息队列标识符。 12 | * cmd为执行的控制命令(在ipc.h中定义): 13 | * [`#define IPC_RMID 0`](#ipc_rmid) 14 | * [`#define IPC_SET 1`](#ipc_set) 15 | * [`#define IPC_STAT 2`](#ipc_stat) 16 | * [`#define IPC_INFO 3`](#ipc_info) 17 | * buf 18 | 19 | cmd字段除了公共的四个操作以外,还有自己独立的操作。 20 | ------------------- 21 | ###IPC_RMID 22 | 删除消息队列。从系统中删除给消息队列以及仍在该队列上的所有数据,这种删除立即生效。 23 | 仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错,并返回**EIDRM**。 24 | 此命令只能由如下两种进程执行: 25 | * 其有效用户ID等于msg_perm.cuid或msg_perm.guid的进程。 26 | * 另一种是具有超级用户特权的进程。 27 | 28 | ###IPC_SET 29 | 设置消息队列的属性。按照**buf**指向的结构中的值,来设置此队列的msqid_id结构。 30 | 该命令的执行特权与上一个相同。 31 | ###IPC_STAT 32 | 读取消息队列的属性。取得此队列的**msqid_ds**结构,并存放在**buf***中。 33 | ###IPC_INFO 34 | 读取消息队列基本情况。 -------------------------------------------------------------------------------- /docs/msgget.md: -------------------------------------------------------------------------------- 1 | 创建消息队列。如果把消息队列看做一个文件的话,那么该函数就相当于**[open](open)**。 2 | ###函数原型 3 | ```c 4 | #include 5 | #include 6 | #include 7 | 8 | int msgget(key_t key, int msgflg); 9 | ``` 10 | ###参数 11 | 第一个参数是key值。 12 | 第二个参数的地位用来确定消息队列的访问权限。可以附加参数: 13 | * IPC_CREAT //如果key不存在,则创建*(类似open函数的O_CREAT)* 14 | * IPC_EXCL //如果key存在,则返回失败*(类似open函数的O_EXCL)* 15 | * IPC_NOWAIT //如果需要等待,则直接返回错误 16 | 17 | 比如:`msgid=msgget(key,0666|IPC_CREAT)` 18 | ###返回值 19 | 成功执行时,返回消息队列标识符。失败返回-1,errno被设为以下的某个值 20 | * EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权能 21 | * EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志 22 | * ENOENT:key指定的消息队列不存在同时msgflg中不指定IPC_CREAT标志 23 | * ENOMEM:需要建立消息队列,但内存不足 24 | * ENOSPC:需要建立消息队列,但已达到系统的限制 -------------------------------------------------------------------------------- /docs/msgsnd-msgrcv.md: -------------------------------------------------------------------------------- 1 | 这是一对函数,用于消息队列的发送和接收 2 | ###描述 3 | msgsnd函数用于将新的消息添加到消息队列的尾端。 4 | msgrcv函数用于从消息队列中读取msqid指定的消息 5 | ###函数原型 6 | ```c 7 | #include 8 | #include 9 | #include 10 | 11 | int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 12 | 13 | ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, 14 | int msgflg); 15 | ``` 16 | ###参数 17 | #### msgsnd 18 | * msqid:消息队列标识符(由[msgget](msget)生成) 19 | * msgp:指向用户自定义的缓冲区([msgp](#msgp)) 20 | * msgsz:接收信息的大小。范围在0~系统对消息队列的限制值 21 | * msgflg:指定在达到系统为消息队列限定的界限时应采取的操作。 22 | * IPC_NOWAIT 如果需要等待,则不发送消息并且调用进程立即返回,errno为**EAGAIN** 23 | * 如果设置为0,则调用进程挂起执行,直到达到系统所规定的最大值为止,并发送消息 24 | 25 | #### msgrcv 26 | * msqid:消息队列标识符 27 | * msgp:指向用户自定义的缓冲区([msgp](#msg)) 28 | * msgsz:如果收到的消息大于msgsz,并且msgflg&MSG_NOERROR为真,则将该消息截至msgsz字节,并且不发送截断提示 29 | * msgtyp:用于指定请求的[消息类型](#msg): 30 | * msgtyp=0:收到的第一条消息,任意类型。 31 | * msgtyp>0:收到的第一条msgtyp类型的消息。 32 | * msgtyp<0:收到的第一条最低类型(小于或等于msgtyp的绝对值)的消息。 33 | * msgflg:用于指定所需类型的消息不再队列上时的将要采取的操作: 34 | * 如果设置了IPC_NOWAIT,若需要等待,则调用进程立即返回,同时返回-1,并设置errno为**ENOMSG** 35 | * 如果未设置IPC_NOWAIT,则调用进程挂起执行,直至出现以下任何一种情况发生: 36 | * 某一所需类型的消息被放置到队列中。 37 | * msqid从系统只能怪删除,当该情况发生时,返回-1,并将errno设为**EIDRM**。 38 | * 调用进程收到一个要捕获的信号,在这种情况下,未收到消息,并且调用进程按`signal(SIGTRAP)`中指定的方式恢复执行。 39 | 40 | ###返回值 41 | 毋庸置疑,成功0,失败-1。 42 | 其他要注意的是,消息队列数据结构(msqid_ds类型)成员的变化: 43 | ####msgsnd 44 | 成功时: 45 | * msg_qnum 以1为增量递增 46 | * msg_lspid 设置为调用进程的pid 47 | * msg_stime 设置为当前时间。 48 | 49 | ####msgrcv 50 | 成功时: 51 | * msg_qnum 以1为增量递减 52 | * msg_lrpid 设置为调用进程的pid 53 | * msg_rtime 设置为当前时间。 54 | 55 | ************* 56 | ####msgp 57 | 该类型需要自己在编程时定义,用于存储消息的内容。 58 | 下面给出一个范例,注意,里面的名称随意。 59 | ```c 60 | struct msgbuf{ 61 | long mtype; //消息类型 62 | char mtext[1];//数组大小编程时自己指定 63 | }; 64 | ``` -------------------------------------------------------------------------------- /docs/open.md: -------------------------------------------------------------------------------- 1 | 基于文件描述符的文件打开方式 2 | ###函数原型 3 | ```c 4 | #include 5 | #include 6 | #include 7 | 8 | int open(const char* pathname,int flags); 9 | int open(const char* pathname,int flags,mode_t mode); 10 | int creat(const char* pathname,mode_t mode); 11 | ``` 12 | >stat是status的缩写 13 | 14 | >fcntl是file control的缩写 15 | 16 | ##参数 17 | ###flags 18 | flags字段使用POSIX的几个宏,此时必须包含头文件``才行。 19 | 可以是下面几个宏的逻辑或组合。这些宏共有三种类型: 20 | 21 | |访问方式|描述 22 | |---|--- 23 | |*O_RDONLY*|只读 24 | |*O_WRONLY*|只写 25 | |*O_RDWR*|可读写 26 | 27 | |打开时标志|描述 28 | |---|--- 29 | |*O_CREAT*|创建文件,需要指定第餐个参数mode 30 | |*O_EXCL*|与`O_CREAT`联用,如果文件已存在则返回错误 31 | |*O_TRUNC*|将清空文件的内容,仅对普通文件有用 32 | |*O_NOCTTY*|若打开的文件是终端设备,不让它作为该进程的控制终端 33 | |*O_NOBLOCK*|以非阻塞模式打开 34 | 35 | |IO操作方式|描述 36 | |---|--- 37 | |*O_APPEND*|把数据写到文件末尾 38 | |*O_NONBLOCK*|对文件的read()/write(),当无立即可用输入(或输出不能立即写出)时能以EAGAIN错误状态标志立即返回 39 | |*O_ASYNC*|(异步)此标志被设置,文件描述符有输入数据时会生成SIGIO信号 40 | |*O_SYNC*| 41 | |*O_DSYNC*| 42 | |*O_RSYNC*| 43 | 44 | >`O_EXCL`的EXCL是Exclusive(排他的,专有的)的缩写 45 | >>如果在打开已有文件的时候,没有使用`O_TRUNC`参数,而只是将fd的偏移置为文件头, 46 | 这样会有问题,即之前的内容没有没删除,而是逐个覆盖。如果第二次输入的内容少于文件本身的内容, 47 | 则会出现问题。 48 | 49 | ----------- 50 | 51 | 一个进程当前有哪些打开的文件描述符可以通过/proc/进程ID/fd目录查看 -------------------------------------------------------------------------------- /docs/pipe.md: -------------------------------------------------------------------------------- 1 | 创建一个管道,Linux系统中有pipe()和pipe2()两个函数。 2 | >Linux仅支持半双工管道 3 | 4 | pipe 5 | ---- 6 | ###函数原型 7 | ```c 8 | #include 9 | 10 | int pipe(int pipefd[2]); 11 | ``` 12 | ###参数 13 | pipefd[0] 读端 14 | pipefd[1] 写端 15 | 16 | ###返回值 17 | 0 成功 18 | -1 失败,并自动设置 errno 19 | ---- 20 | ---- 21 | pipe2 22 | ---- 23 | pipe2非POSIX标准,仅被Linux支持 24 | ###函数原型 25 | ```c 26 | #include 27 | #include 28 | #define _GNU_SOURCE 29 | 30 | int pipe2(int pipefd[2],int flags); 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /docs/poll.md: -------------------------------------------------------------------------------- 1 | poll()和select()原理相同,但实现方式不同。select()用的更为频繁,但`据说`poll()效率更高,不过自`Linux 2.5.44`后被epoll取代。 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int poll(struct pollfd *fds, nfds_t nfds, int timeout); 7 | ``` 8 | ##参数 9 | ###fds 10 | [pollfd](#pollfd)结构的数组。 11 | 检测每个结构中的fd对应的events事件是否就绪。在poll返回的时候将就绪情况写入到revents中。 12 | ###nfds 13 | nfds_t是`unsigned long`类型,据《UNP》所言,该类型过大了。 14 | ###timeout 15 | - -1:永远等待(一说:负数) 16 | - 0:不等待,立即返回 17 | - >0:等待指定数目的毫秒数 18 | 19 | ##返回值 20 | - 0: 表示超时返回 21 | - -1:表示出错 22 | - >0:表示就绪的的文件描述符的数量 23 | 24 | >poll()与select()返回正数时,其含义有差别: 25 | - select(): 如果同一个文件描述符在多个fd集(select有三个fd集合)中返回,则返回值也统计多次 26 | - poll():即使同一个fd出现在多个pollfd元素的`revents`成员中,也只被统计一次。 27 | 28 | ---------- 29 | ##pollfd 30 | 非`typedef`的结构体类型 31 | 32 | |成员|类型|说明 33 | |----|----|---- 34 | |fd|int| 35 | |events|short| 36 | |revents|short| 37 | events和revents都是`bit masks`。events是输入,revents是输出(返回),events由用户设置,revents在函数返回时被设置。其取值可以是如下宏的按位或的结果: 38 | 39 | |输入事件bit位|events的输入?|revents的结果?|说明 40 | |---|:-------:|:------:|:------: 41 | |POLLIN|√|√|有数据可读 42 | |POLLRDNORM|√|√|等价于**POLLIN** 43 | |POLLPRI|√|√|高优先级数据可读 44 | |POLLRDHUP|√|√|对等套接字关闭 45 | |**输出事件bit位**|**events的输入?**|**revents的结果?**|**说明** 46 | |POLLOUT|√|√|普通数据可写 47 | |POLLWRNORM|√|√|等价于**POLLOUT** 48 | |POLLWRBAND|√|√|优先级数据可写 49 | |**错误事件bit位**|**events的输入?**|**revents的结果?**|**说明** 50 | |POLLERR||√|发生错误 51 | |POLLHUP||√|发生挂起 52 | |POLLNVAL||√|(invalid)fd没有被打开 53 | 54 | >POLLRDHUP 从`Linux 2.6.17`开始被支持 55 | 差异性:《UNP》中提到的POLLRDBAND其实并不被Linux支持;此外《UNP》中POLLIN与POLLRDNORM,POLLOUT与POLLWRNORM也并非等价。 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/psignal.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | void psignal(int sig, const char *msg); 6 | ``` 7 | ##描述 8 | 打印sig对应信号的描述信息到标准错误流。 9 | ##参数 10 | sig为信号对应的数。 11 | msg如果不为NULL,那么将msg作为输出消息的前缀。在msg和消息描述之间默认会有一个冒号和一个空格。 12 | 13 | ##相关函数 14 | [[psiginfo|psiginfo]] -------------------------------------------------------------------------------- /docs/pthread_create.md: -------------------------------------------------------------------------------- 1 | 在调用这个函数的进程中创建一个新的线程 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 7 | void *(*start_routine) (void *), void *arg); 8 | ``` 9 | ##参数 10 | ###thread 11 | 属于**结果参数**。函数结束时,返回线程ID并存储到thread中。 12 | `pthread_t`被定义成`unsigned long int`类型。 13 | ###attr 14 | 设置线程的属性,主要是栈相关的属性。 15 | ###start_routine 16 | start_routine是一个回调函数(函数指针实现)。指明了线程要执行的函数。 17 | ###arg 18 | 回调函数start_routine()执行时的参数(实参)。 19 | ##返回值 20 | 成返回0,失败返回非0值。 -------------------------------------------------------------------------------- /docs/pthread_exit.md: -------------------------------------------------------------------------------- 1 | 结束一个线程 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | void pthread_exit(void *retval); 7 | ``` 8 | ##参数 9 | retval用来保存线程退出状态 10 | ##返回值 11 | 为空。因为该函数**永远成功**。 -------------------------------------------------------------------------------- /docs/pthread_join.md: -------------------------------------------------------------------------------- 1 | 为了回收资源,主线程会等待子线程结束。该函数就是用来等待线程终止的。类似与进程中的wait函数。 2 | 此函数将阻塞调用当前线程的进程,直到此线程退出。 3 | ##函数原型 4 | ```c 5 | #include 6 | 7 | int pthread_join(pthread_t thread, void **retval); 8 | ``` 9 | ##参数 10 | ###thread 11 | 被等待线程的ID 12 | ###retval 13 | 如果此值非NULL,pthread_join复制线程的退出状态 14 | ##返回值 15 | 成功返回0,失败返回非0 16 | -------------------------------------------------------------------------------- /docs/pthread_mutex_init.md: -------------------------------------------------------------------------------- 1 | 用指定属性初始化互斥锁 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int pthread_mutex_init(pthread_mutex_t *restrict mutex, 7 | const pthread_mutexattr_t *restrict attr); 8 | ``` 9 | ##参数 10 | |形参|描述 11 | |---|----- 12 | |mutex|指向要初始化的互斥锁指针 13 | |attr|指针类型,为要初始化的互斥锁定义属性,如果为NULL则为默认属性 14 | 15 | restrict是C99关键字,视其变量不与其他变量关联,用于提高编译效率 16 | 17 | ------------ 18 | ##PTHEREAD_MUTEX_INITIALIZER 19 | 静态初始化宏,初始化互斥锁,而无须调用pthread_mutex_init() 20 | ```c 21 | #ifdef __PTHREAD_MUTEX_HAVE_PREV 22 | # define PTHREAD_MUTEX_INITIALIZER \ 23 | { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } 24 | # ifdef __USE_GNU 25 | # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ 26 | { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } } 27 | # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ 28 | { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } } 29 | # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ 30 | { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } } 31 | # endif 32 | #else 33 | # define PTHREAD_MUTEX_INITIALIZER \ 34 | { { 0, 0, 0, 0, 0, { 0 } } } 35 | # ifdef __USE_GNU 36 | # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ 37 | { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } } 38 | # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ 39 | { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } } 40 | # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ 41 | { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } } 42 | # endif 43 | #endif 44 | ``` -------------------------------------------------------------------------------- /docs/pthread_mutexattr_settype.md: -------------------------------------------------------------------------------- 1 | 设置互斥锁属性对象(**pthread_mutexattr_t**)的属性 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); 7 | ``` 8 | ##参数 9 | - attr是要设置属性的互斥锁属性对象 10 | - kind是互斥锁的种类(即属性) 11 | 12 | ##返回值 13 | 成功返回0,失败返回**非0**的错误代码 14 | 15 | ##属性种类 16 | Linux支持3种互斥锁锁,它们的名称以后缀**_NP**结尾,表示non-portable,是不标准的锁名称。但实际上它们在实现的时候常常和POSIX标准的三种锁等价。 17 | 18 | |Linux 互斥锁|对应的POSXI互斥锁 19 | |-----|------ 20 | |PTHREAD_MUTEX_FAST_NP|PTHREAD_MUTEX_NORMAL 21 | |PTHREAD_MUTEX_RECURSIVE_NP|PTHREAD_MUTEX_RECURSIVE 22 | |PTHREAD_MUTEX_ERRORCHECK_NP|PTHREAD_MUTEX_ERRORCHECK 23 | 为保持程序兼容性,应该避免使用NP后缀的互斥锁名称。 24 | ###正常锁 25 | (PTHREAD_MUTEX_NORMAL) 26 | 27 | 这种互斥锁不能自己检测死锁,如果一个线程尝试给已经加锁的互斥锁再次加锁,就会导致死锁。解锁一个被其他线程加锁的互斥锁会导致未定义结果。 28 | >Linux中另有一互斥锁**PTHREAD_MUTEX_DEFAULT**与该锁等价。 29 | 30 | ###递归锁 31 | (PTHREAD_MUTEX_RECURSIVE) 32 | 递归锁维护一个锁的数量。同一线程可以多次加锁,每加锁一次,锁的数量加1。解锁一次,锁的数量减一,直到锁的数量为0,该锁被释放。 33 | 当线程解锁其他线程的递归锁的时候,解锁会失败。 34 | ###错误检查锁 35 | (PTHREAD_MUTEX_ERRORCHECK) 36 | 37 | 锁的每一个操作都会进行错误检查,因此错误检查锁较慢,但是容易调试,便于发现一个应用程序在哪里违反了锁的规则。 -------------------------------------------------------------------------------- /docs/raise.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int raise(int sig); 6 | ``` 7 | ##描述 8 | 发送一个sig信号给当前进程。raise()是线程安全的函数。与kill()的不同之处是,kill()发射信号给指定的进程(通过pid参数) 9 | 10 | 当raise()发射的信号,导致了一个信号句柄被调用的时候,raise()在信号句柄返回之后被返回。 11 | ##返回值 12 | 成功0,失败返回**非0值**(不一定是-1) 13 | ##相关函数 14 | [[kill|kill]] -------------------------------------------------------------------------------- /docs/read.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | ssize_t read(int fd, void *buf, size_t count); 6 | ``` 7 | ##参数 8 | |参数|描述| 9 | |:---:|----| 10 | |fd|文件描述符| 11 | |buf|读取的数据存放在buf指针指向的缓冲区| 12 | |count|读取的字节数| 13 | 14 | **关于count:如果buf是一个字符数组名,那么count就用它的sizeof值。若buf是字符指针(字符串)则count用它的strlen值。** 15 | ##返回值 16 | 若果函数执行成功,返回读取的**字节数**,如果遇到EOF,则返回**0**。出错返回**-1**,并设置相应errno值。 17 | * 当我指定要读取100个字节的时候,在读完30个字节后,遇到了EOF,那么这时立即返回30,接下来继续执行read函数的时候返回0。 18 | * 从终端设备读,通常以行为单位,读到换行符就返回。 19 | * 当出错时(即返回-1),如果errno的值是**EINTR**,表示遇到调用信号而中断了读取,那么我们可以再次尝试read。 20 | 21 | ##相关函数 22 | |[[write|write]]|[[fread|fwrite-fread#fread]]| 23 | |----------|------------| -------------------------------------------------------------------------------- /docs/recv.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); 6 | ``` 7 | ##参数 8 | 前三个参数和[[read|read]]相同。最后一个参数是标志。 9 | 10 | |flags|描述 11 | |------|----- 12 | |0|则等价于read 13 | |MSG_PEEK|窥视套接字上的数据而不实际读出它们 14 | |MSG_OOB|读带外数据 15 | |MSG_WAITALL|函数阻塞直至接收到所请求的全部数据 16 | 17 | flags参数由以上标志按**逻辑或**操作形成。 18 | ##相关函数 19 | |[[send|send]]|[[write|write]]|[[read|read]] 20 | |---------|-------|--------- -------------------------------------------------------------------------------- /docs/recvfrom.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, 6 | struct sockaddr *src_addr, socklen_t *addrlen); 7 | ``` 8 | ##描述 9 | recvfrom()的前面四个参数同[[recv()|recv]],对于简单的数据报C/S例子,flags字段总为0。 10 | 11 | 参数src_addr和addrlen类似[[accept()|accept]]的最后两个参数: 12 | 在**函数返回**时,它们给出套接字的地址以告知是谁发送的数据报。如果对这一信息不感兴趣,可以指定成空指针。 13 | ##返回值 14 | 同recv(),表示实际读的字节数。失败的时候返回-1,并设置errno -------------------------------------------------------------------------------- /docs/rename.md: -------------------------------------------------------------------------------- 1 | 给文件改名,移动文件位置。 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int rename(const char *oldpath, const char *newpath); 7 | ``` 8 | ##返回值 9 | 成功返回0,失败返回-1,并设置相应errno。 -------------------------------------------------------------------------------- /docs/select.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int select(int nfds, fd_set *readfds, fd_set *writefds, 6 | fd_set *exceptfds, struct timeval *timeout); 7 | ``` 8 | ##参数 9 | ###nfds 10 | 指定被监听的文件描述符的总数。它通常被设置为select()监听的最大文件描述符加1(文件描述符从0计数) 11 | ###readfds、writefds、exceptfds 12 | 分别指向可读、可写和异常事件对应的文件描述符集合。这三个参数都是[fd_set](#fd_set)类型。 13 | 这三个参数是**值-结果**参数,在select()返回的的时候,将把就绪的fd更新到对应的集合中。 14 | ###timeout 15 | 设置select()超时时间。 16 | - NULL: select()将无限等待 17 | - 非NULL: select()等待相应秒数,若无就绪则超时返回 18 | - **特例**非NULL,但其值为0秒: select()检查完fd集合后立即返回 19 | 20 | 这是个**值-结果参数**,select()成功返回时,内核将修改它的值为**剩余**的时间。 21 | 但当该调用失败的时候,它返回的值是不确定的。该结构体(timeval)提供微秒级的分辨率。 22 | ##返回值 23 | - 成功时返回就绪(可读、可写和异常)文件描述符的总数。 24 | - 如果在超时时间内没有任何文件描述符就绪,select()将返回0。 25 | - 失败时返回-1,并设置errno。 26 | 27 | 如果在select()等待期间,程序接收到信号,则select()立即返回-1,并设置errno为**EINTR**。 28 | 29 | ---- 30 | ###fd_set 31 | 一个结构体名(被typedef命名,所以使用时不加struct)。实际上里面只包含一个整型(long int)数组。 32 | 该数组的每一位标记一个文件描述符。可以通过以下**函数宏**来访问fd_set结构体中的位。 33 | 34 | | 返回值|函数宏|描述 35 | |-----|----|----- 36 | void|**FD_ZERO**(fd_set *set)|清除set所有的位 37 | void|**FD_CLR**(int fd, fd_set *set)|清除set的为fd 38 | void|**FD_SET**(int fd, fd_set *set)|设置set的位fd 39 | int |**FD_ISSET**(int fd, fd_set *set)|测试set的位fd是否被设置 40 | 41 | 在使用fd_set类型的变量的时候,一定要用`FD_ZERO`初始化 -------------------------------------------------------------------------------- /docs/sem_open.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include /* For O_* constants */ 4 | #include /* For mode constants */ 5 | #include 6 | 7 | sem_t *sem_open(const char *name, int oflag); 8 | sem_t *sem_open(const char *name, int oflag, 9 | mode_t mode, unsigned int value); 10 | ``` 11 | ##参数 12 | 和[[open()|open]]函数参数基本相同。唯一的限制是参数name必须是字符`/`打头。 -------------------------------------------------------------------------------- /docs/semctl.md: -------------------------------------------------------------------------------- 1 | 控制信号量集合、信号量 2 | ##函数原型 3 | ```c 4 | #include 5 | #include 6 | #include 7 | 8 | int semctl(int semid, int semnum, int cmd, ...); 9 | ``` 10 | ##参数 11 | 可以有三个参数,也可以有四个参数(利用的可变参数个数的函数定义)。 12 | * semid是信号量集合的标识符,一般由[semget](semget)函数返回。 13 | * semnum为集合中信号量的编号。 14 | * 如果标识某个信号量,此值为信号量下标(0~n-1) 15 | * 如果标识整个信号量集合,则设置为0【与上面冲突?】 16 | * cmd为要执行的操作: 17 | * 共有的IPC四个操作 18 | * `GETVAL` //返回的是semnum的值 19 | * `GETALL` //设置semnum为0,那么获取信号集合的地址传递给第四个参数。返回值为0,-1 20 | * `GETNCNT` //设置semnum为0,返回值为等待信号量值的递增进程数,否则返回-1 21 | * `GETZCNT` //设置semnum为0,返回值是等待信号量值的递减进程数,否则返回-1 22 | * `SETVAL` //将第四个参数指定的值设置给编号为semnum的信号量。返回值为0,1 23 | * `SETALL` //设置semnum为0,将第四个参数传递个所有信号量。返回值0,1 24 | 25 | >GET的四个操作中,只有GETVAL成功时返回0,其余的都是返相应取的值。SET两个操作都返回的是值 26 | 27 | * [第四个参数],根据cmd的不同而不同。其类型为[semun](#semun)的联合: 28 | * 如果cmd为SETVAL,那么该参数为val 29 | * 如果cmd为IPC_STAT&IPC_SET,那么该参数为struct semid_ds结构体变量 30 | * 如果cmd为GETVAL&SETALL,则该参数为数组地址array。 31 | * 如果cmd为IPC_INFO,则该参数为strcut seminfo结构体变量__buf 32 | 33 | 34 | ------------ 35 | ###semun 36 | ``` 37 | union semun { 38 | int val; /* Value for SETVAL */ 39 | struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 40 | unsigned short *array; /* Array for GETALL, SETALL */ 41 | struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ 42 | }; 43 | ``` -------------------------------------------------------------------------------- /docs/semget.md: -------------------------------------------------------------------------------- 1 | >System V提供的三种IPC进制,有异曲同工之妙。 2 | 3 | semget 4 | ----- 5 | 创建信号量结合 6 | ###函数原型 7 | ```c 8 | #include 9 | #include 10 | #include 11 | 12 | int semget(key_t key, int nsems, int semflg); 13 | ``` 14 | ###参数 15 | 参数含义,与[msgget](msgget)类似,只是比它多了第二个参数。 16 | * key为[ftok](ftok)函数创建。 17 | * nsems为创建的信号量的个数,每个信号量以数组方式存储。 18 | * semflg用来标识信号量结合的权限。如**0700**。此外还可以附加以下ipc参数: 19 | 20 | |宏名|描述| 21 | |---------|-------| 22 | |IPC_CREAT|如果key不存在,则创建*(类似open函数的O_CREAT)* 23 | |IPC_EXCL|如果key存在,则返回失败*(类似open函数的O_EXCL)* 24 | |IPC_NOWAIT|如果需要等待,则直接返回错误 25 | -------------------------------------------------------------------------------- /docs/semop.md: -------------------------------------------------------------------------------- 1 | 该函数的操作对象为信号量,而非信号量集合。这是一个原子操作。 2 | 为`semaphore operate`的缩写 3 | ##函数原型 4 | ```c 5 | #include 6 | #include 7 | #include 8 | 9 | int semop(int semid, struct sembuf *sops, unsigned nsops); 10 | 11 | int semtimedop(int semid, struct sembuf *sops, unsigned nsops, 12 | struct timespec *timeout); 13 | ``` 14 | ##参数 15 | ###semid 16 | 要操作的信号量集合标识符 17 | ###sops 18 | 此结构体为: 19 | ```c 20 | struct sembuf { 21 | unsigned short sem_num; /* 数组中的信号量下标 */ 22 | short sem_op; /* 信号量操作 */ 23 | short sem_flg; /* 操作标识 */ 24 | }; 25 | ``` 26 | 成员解读: 27 | * sembuf为信号量的编号 28 | * sem_op是要进行的操作([PV操作](#pv)): 29 | * 如果为正整数,表示增加信号量的值(若为3,则加上3) 30 | * 如果为负整数,表示减小信号量的值 31 | * 如果为0,表示对信号量当前值进行是否为0的测试 32 | * sem_flg为操作标识: 33 | * IPC_NOWAIT:如果不能对信号量集合进行操作,则立即返回 34 | * SEM_UNDO:当进程退出后,该进程对sem进行的操作将撤销 35 | 36 | ###nsops 37 | 38 | ---------- 39 | ###PV 40 | 信号量是最早出现的用来解决进程同步与互斥问题的机制。 41 | P原语操作的动作是: 42 | 43 | 1. sem减1; 44 | 2. 若sem减1后仍大于或等于零,则进程继续执行; 45 | 3. 若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。 46 | 47 | V原语操作的动作是: 48 | 49 | 1. sem加1; 50 | 2. 若相加结果大于零,则进程继续执行; 51 | 3. 若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。 52 | -------------------------------------------------------------------------------- /docs/send.md: -------------------------------------------------------------------------------- 1 | ##函数模型 2 | ```c 3 | #include 4 | 5 | int send(int s, const void *msg, size_t len, int flags); 6 | ``` 7 | ##参数 8 | 前面三个参数同[[write|write]]。最后一个是标志(flag)。它的取值是几个宏 9 | 10 | |flags|描述 11 | |-----|----- 12 | |MSG_OOB|导致send()发送的数据成为带外数据 13 | |MSG_DONTROUTE|不在消息中包含路由信息 14 | 15 | flags参数由以上标志按**逻辑或**操作形成。 16 | ##[[带外数据|带外数据]] 17 | 18 | ##相关函数 19 | |[[recv|recv]]|[[write|write]]|[[read|read]] 20 | |---------|-------|--------- -------------------------------------------------------------------------------- /docs/sendto.md: -------------------------------------------------------------------------------- 1 | ## 2 | ```c 3 | #include 4 | 5 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, 6 | const struct sockaddr *dest_addr, socklen_t addrlen); 7 | ``` 8 | ##描述 9 | sendto()的前面四个参数同[[sendto()|sendto]],对于简单的数据报C/S例子,flags字段总为0。 10 | 11 | 参数src_addr和addrlen类似[[connect()|connect]]的最后两个参数: 12 | 在**发送数据报**时,要在套接字地址结构dest_addr中填入协议地址以指明数据报发给谁。 13 | 14 | 注意addrlen是整数,而recvfrom的最后一个参数addrlen是指向整数的指针。这个差别就是**[[值-结果参数|值-结果参数]]** 15 | ##返回值 16 | 同send(),表示实际发送的字节数。失败的时候返回-1,并设置errno -------------------------------------------------------------------------------- /docs/shmat-shmdt.md: -------------------------------------------------------------------------------- 1 | shmat是shared memory attach的缩写。而attach本意是贴的意思。 2 | 如果进程要使用一段共享内存,那么一定要将该共享内存与当前进程建立联系。即经该共享内存挂接(或称映射)到当前进程。 3 | shmdt则是shmat的反操作,用于将共享内存和当前进程分离。在共享内存使用完毕后都要调用该函数。 4 | ##函数原型 5 | ```c 6 | #include 7 | #include 8 | 9 | void *shmat(int shmid, const void *shmaddr, int shmflg); 10 | 11 | int shmdt(const void *shmaddr); 12 | ``` 13 | ##参数 14 | ###shmid 15 | 共享内存空间的标识符,即ID。 16 | ###shmaddr 17 | 指定共享内存的映射地址。 18 | shmat中:如果为0(NULL),则由系统选择映射的地址,推荐设置为0。如果非0,并且没有指定**SHM_RND**,则该值即为映射共享内存的地址。 19 | ###shmflg 20 | 指定共享内存的访问权限和映射条件: 21 | * SHM_RDONLY //只读 22 | * SHM_RND //取整,取向下一个[SHMLBA](#shmlba)边界 23 | * SHM_REMAP //take-over region on attach 24 | * SHM_EXEC //执行权限 25 | 26 | 如果设置为0的话,则是**读写**权限。 27 | ##返回值 28 | * shmat 29 | * 成功,则返回共享内存的地址 30 | * 失败,则返回-1,并设置errno 31 | * shmdt 32 | * 成功,则返回0 33 | * 失败,则返回-1,并设置errno 34 | 35 | ----------------- 36 | ###SHMLBA 37 | 低边界地址倍数,它总是2的乘方。 -------------------------------------------------------------------------------- /docs/shmctl.md: -------------------------------------------------------------------------------- 1 | 共享内存的控制 2 | ##函数原型 3 | ```c 4 | #include 5 | #include 6 | 7 | int shmctl(int shmid, int cmd, struct shmid_ds *buf); 8 | ``` 9 | ##参数 10 | ###shmid 11 | 由shmget函数生成,不同的key值对应不同的id值。 12 | ###cmd 13 | 操作字段,包括: 14 | * 公共的IPC选项(ipc.h中): 15 | * `IPC_RMID //删除` 16 | * `IPC_SET //设置ipc_perm参数` 17 | * `IPC_STAT //获取ipc_perm参数` 18 | * `IPC_INFO //如ipcs` 19 | * 共享内存自己的选项(shm.h中)【需要root权限】 20 | * `SHM_LOCK //锁定共享内存段` 21 | * `SHM_UNLOCK //解锁共享内存段` -------------------------------------------------------------------------------- /docs/shmget.md: -------------------------------------------------------------------------------- 1 | 创建共享内存,通过key返回id。 2 | ##函数原型 3 | ```c 4 | #include 5 | #include 6 | 7 | int shmget(key_t key, size_t size, int shmflg); 8 | ``` 9 | ##参数 10 | ###key 11 | 不消多说 12 | ###size 13 | 欲创建的共享内存段的大小 14 | ###shmflg 15 | 共享内存段的创建标识: 16 | * 公共的IPC选项(在**/usr/include/linux/ipc.h中定义**) 17 | * `IPC_CREAT //如果不存在就创建` 18 | * `IPC_EXCL //如果存在则返回失败` 19 | * `IPC_NOWAIT //如不等待直接返回` 20 | * 共享内存自己的选项(在**/usr/include/linux/shm.h中定义**) 21 | * `SHM_R //可读` 22 | * `SHM_W //可写` 23 | -------------------------------------------------------------------------------- /docs/shutdown.md: -------------------------------------------------------------------------------- 1 | 断开套接字连接 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int shutdown(int socket,int how); 7 | ``` 8 | ##参数 9 | shutdown()函数可以部分或全部断开套接字socket的连接。它可以只关闭此连接的接收或发送。具体视参数how而定。 10 | how取值: 11 | - SHUT_RD:停止从此套接字接收数据 12 | - SHUT_WR:停止从此套接字发送数据 13 | - SHUT_RDWR:停止从该套接字接收和发送数据 14 | 15 | -------------------------------------------------------------------------------- /docs/sigaction.md: -------------------------------------------------------------------------------- 1 | 本节包括sigaction函数和结构体sigaction两个部分。 2 | 函数sigaction 3 | ------------ 4 | System Call用于测试和改变一个信号的行为。 5 | ###函数原型 6 | ```c 7 | #include 8 | 9 | int sigaction(int signum, const struct sigaction *act, 10 | struct sigaction *oldact); 11 | ``` 12 | |参数|描述| 13 | |----|---| 14 | |signum|指定要改变的信号 15 | |act|一个函数指针,如果不为空,则指定收到该信号后的行为 16 | |oldact|如果oldact不为空,则将原行为保存在函数指针oldact中 17 | ******** 18 | 结构体sigaction 19 | -------------- 20 | ###结构体原型 21 | ```c 22 | struct sigaction { 23 | void (*sa_handler)(int); 24 | void (*sa_sigaction)(int, siginfo_t *, void *); 25 | sigset_t sa_mask; 26 | int sa_flags; 27 | }; 28 | ``` 29 | ####sa_handler 30 | 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。 31 | ####sa_sigaction 32 | 是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。 33 | >在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。 34 | 35 | ####sa_mask 36 | 成员用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。 37 | ####sa_flags 38 | 成员用于指定信号处理的行为,它可以是以下值的“按位或”组合。 39 | * SA_RESTART:使被信号打断的系统调用自动重新发起。 40 | * SA_ONSTACK:系统将在调用[[sigalstack|sigalstack]]替代信号栈上运行信号句柄;否则使用用户栈来交付信号。 41 | * SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。 42 | * SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。 43 | * SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。 44 | * SA_RESETHAND:信号处理之后重新设置为默认的处理方式。 45 | * SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。 46 | 47 | >该段文字整理自[博客园](http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html) 48 | 49 | ##相关函数 50 | - [[signal|signal]] 51 | - [[sigemptyset|sigemptyset]] -------------------------------------------------------------------------------- /docs/signal.md: -------------------------------------------------------------------------------- 1 | 对一个信号指定新动作或回到其原先的动作 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | typedef void (*sighandler_t)(int); 7 | sighandler_t signal(int signum, sighandler_t handler); 8 | ``` 9 | 10 | ##参数 11 | signum即信号值。后面的handler就是处理这个信号的动作。它的值为: 12 | - SIG_DFL:默认动作 13 | - SIG_IGN:忽略该信号(SIGKILL和SIGSTOP无法忽略,因为要保证root的绝对控制权) 14 | - 信号句柄 15 | 16 | ##信号句柄 17 | 信号句柄即捕获函数(这里是函数指针类型),该函数必须是只有一个整型参数,且返回值为void。 18 | 19 | 信号发送时,如果建立了信号句柄,系统在把控制转移到信号句柄之前有两种做法: 20 | - 将阻塞后继新的信号直至信号句柄完成为止 21 | - 或这首先改变该信号的动作为SIG_DEL(相当于调用signal(signum,SIG_DEL),在执行完一次信号句柄之后,将其恢复为默认动作) 22 | 23 | BSD系统使用前者,系统V使用后一种。Linux默认采用BSD的做法,但当设置了特征测试宏`_XOPEN_SOURCE`时,则采用系统V的做法,此时编译时要这样编译 24 | ``` 25 | gcc test.c -D_XOPEN_SOURCE 26 | ``` 27 | ##返回值 28 | 返回值是指向信号signum前一次有效动作的指针。它和函数第二个参数类型相同。返回值是: 29 | - SIG_DFL 30 | - SIG_IGN 31 | - 信号句柄指针 32 | 33 | **可以保存这个值,并且在以后用它作为函数第二个参数再次调用signal(),从而恢复信号原来的动作** 34 | 35 | 如果出错,返回**SIG_ERR**并设置**errno**。唯一地错误码(errno)是**EINVAL** 36 | ##相关函数 37 | [[sigaction|sigaction]] -------------------------------------------------------------------------------- /docs/sigprocmask.md: -------------------------------------------------------------------------------- 1 | 用于阻塞信号(除SIGKILL和SIGSTOP外) 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 7 | ``` 8 | ##参数 9 | ###how 10 | 指明如何改变信号屏蔽,它的值必须是下列之一: 11 | 12 | |how|描述 13 | |----|---- 14 | |SIG_BLOCK|阻塞set所指信号集中的信号(将它们加入当前信号屏蔽中) 15 | |SIG_UNBLOCK|放在set所指信号集中的信号(将它们从当前信号屏蔽中去除) 16 | |SIG_SETMASK|用set所指信号集作为进程的新信号屏蔽(抛弃原先信号屏蔽值) 17 | ###set和oldset 18 | - set为NULL时,how没有意义 19 | - oldset用于返回进程原先的信号屏蔽 20 | - 若我们只想改变信号屏蔽而不查看它,则传递NULL给oldset 21 | - 若我们只想查看当前信号屏蔽而不改变它,则传递NULL给set 22 | 23 | ##返回值 24 | 成功0,失败-1,并设置errno -------------------------------------------------------------------------------- /docs/sigsuspend.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int sigsuspend(const sigset_t *mask); 6 | ``` 7 | ##描述 8 | 用mask所指的信号集临时替代调用进程的信号屏蔽,然后挂起调用进程直到有不属于mask的信号到达为止。 9 | ##返回值 10 | **一直返回-1**,有错误会设置errno 11 | ##相关函数 12 | [[pause()|pause]] -------------------------------------------------------------------------------- /docs/socket.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include /* See NOTES */ 4 | #include 5 | 6 | int socket(int domain, int type, int protocol); 7 | ``` 8 | 该函数在通信域domain中创建一个类型为type、使用协议protocol的套接字。 9 | ##参数 10 | ###domain 11 | |常用domain|描述 12 | |:---:|---- 13 | |AF_UNIX|Unix域套接字。同**AF_LOCAL** 14 | |AF_INET|使用IPv4协议的网络通信 15 | |AF_INET6|使用IPv6协议的网络通信 16 | 17 | Unix域套接字,用于同一主机上的两个进程间的通信,在同一主机上IPC的时候,它比使用TCP连接通信效率更高。POSIX将其重命名为**AF_LOCAL**以消除它对应Unix操作系统的依赖。实际是一样的。 18 | >AF是Address Family(地址族)的缩写。另有PF(Protocol Family协议族)开头的值,并不常用。 19 | >>POSIX规范指定socket函数的第一个参数使用PF_值,而套接字地址结构(比如sockddr_in)的地址结构使用AF_值。实际上AF_两者都在使用 20 | 21 | ###type 22 | |常用type|描述 23 | |:---:|---- 24 | |SOCK_STREAM|字节流套接字(流式套接字) 25 | |SOCK_DGRAM|数据报套接字 26 | |SOCK_RAW|原始套接字 27 | ###protocal 28 | 通常设置为0。自动采用合理协议 29 | ###domain和type合法组合 30 | ||AF_INET|AF_INET6|AF_UNIX 31 | |---|:---:|:---:|:---: 32 | |**SOCK_STREAM**|TCP|TCP|yes 33 | |**SOCK_DRAG**|UDP|UDP|yes 34 | |**SOCK_RAW**|IPv4|IPv6| 35 | yes表示支持这一组合,但无相应协议名 36 | ##返回值 37 | 失败返回-1,并设置errno。成功返回一个描述符(类似文件描述符)。socket()和open()一样也返回最小的未使用的描述字,因此**给定的描述符要么代表一个打开的文件,要么代表一个套接字**。 38 | 39 | ----------- 40 | 套接字可以用**close()**函数来销毁。如果只想断开套接字连接,而不销毁它,可以用**shutdown()**函数。 -------------------------------------------------------------------------------- /docs/socketpair.md: -------------------------------------------------------------------------------- 1 | 创建一对套接字 2 | ##函数原型 3 | ```c 4 | #include /* 基本不用,一些特殊的type需要包含此头文件 */ 5 | #include 6 | 7 | int socketpair(int domain, int type, int protocol, int filedes[2]); 8 | ``` 9 | ##参数 10 | domain、type和protocol的含义同[socket](socket)函数。不过Linux的doman参数仅仅支持**AF_UNIX(AF_LOCAL)**。 11 | protocol值常为0,允许系统使用默认协议。 12 | 13 | ------------------- 14 | ##套接字与管道 15 | 两者类似,但不同。管道生成的两个描述字(描述符)分别掌管着写(fd[0])和读(fd[1]),而套接字偶对生成的两个描述字分别代表着父进程(fd[1])和子进程(fd[0]),可分别进行IO。 16 | fd[1]可以用来父进程的IO。fd[0]可以用来子进程的IO。而不是单独代表I或O。 -------------------------------------------------------------------------------- /docs/sockopt.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int getsockopt(int sockfd, int level, int optname, 6 | void *optval, socklen_t *optlen); 7 | int setsockopt(int sockfd, int level, int optname, 8 | const void *optval, socklen_t optlen); 9 | ``` 10 | ##描述 11 | ###getsockopt 12 | 获得套接字sockfd在层次level上的选项optname的值。此选项之值存放子optval所指的缓冲区中。 13 | ###setsockopt 14 | 设置套接字sockfd在层次level上的选项optname的值。选项值传递optval所指缓冲区中,optlen给出缓冲区的大小。 15 | ##SOL_SOCKET层套接字选项 16 | |optname|描述|数据类型 17 | |-----|---------|----------- 18 | |SO_BROADCAST|允许发送广播数据报|int 19 | |SO_DEBUG|打开调试追踪|int 20 | |SO_DONTROUTE|绕过协议的路由机制|int 21 | |SO_KEEPALIVE|周期性地测试连接是否仍建立|linger 22 | |SO_LINGER|如果有数据要发送,是否延迟关闭|int 23 | |SO_OOBINLINE|嵌入方式接收带外数据|int 24 | |SO_RCVBUF|接收缓冲区大小|int 25 | |SO_SNDBUF|发送缓冲区大小|int 26 | |SO_RCVTIMEO|接收超时|timeval 27 | |SO_SNDTIMEO|发送超时|timeval 28 | |SO_TYPE|套接字类型|int 29 | 以上选项除了SO_TYPE仅适用于getsockopt函数外,其余选项两个函数都适用。 30 | -------------------------------------------------------------------------------- /docs/stat.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | #include 6 | 7 | int stat(const char *path, struct stat *buf); 8 | int fstat(int fd, struct stat *buf); 9 | int lstat(const char *path, struct stat *buf); 10 | ``` 11 | 三个函数的关系与chown,fchown,lchown的关系相同。 12 | * stat检查符号链接时,实际检查的是符号链接所引用的文件 13 | * lstat检查符号链接时,检查的是符号链接本身 14 | * fstat功能与stat相同,不过它的参数是文件的描述符 15 | 16 | ##返回值 17 | 成功返回**0**;失败返回**-1**,并设置相应errno的值。 18 | >结构体stat的内容 19 | ```c 20 | struct stat { 21 | dev_t st_dev; /* 设备号(主设备号,次设备号)*/ 22 | ino_t st_ino; /* inode的数量 */ 23 | mode_t st_mode; /* 文件的类型和存取的权限 */ 24 | nlink_t st_nlink; /* 硬链接的数量 */ 25 | uid_t st_uid; /* 所用者的uid */ 26 | gid_t st_gid; /* 所有者的组id */ 27 | dev_t st_rdev; /* device ID (if special file) */ 28 | off_t st_size; /* 总大小,字节数 */ 29 | blksize_t st_blksize; /* blocksize for filesystem I/O */ 30 | blkcnt_t st_blocks; /* number of 512B blocks allocated */ 31 | time_t st_atime; /* 最后访问时间(access)*/ 32 | time_t st_mtime; /* 最后修改时间(modification)文件内容的改动时间 */ 33 | time_t st_ctime; /* 最后改动时间(change)文件属性的改动时间 */ 34 | }; 35 | ``` -------------------------------------------------------------------------------- /docs/time.md: -------------------------------------------------------------------------------- 1 | ##函数原型ANSI C 2 | ```c 3 | #include 4 | 5 | time_t time(time_t *t); 6 | ``` 7 | ##参数 8 | 如果t是非空指针,那么该函数的返回值也将保存在t中。 9 | ##返回值 10 | 返回自epoch(1970年1月1日00:00:00)以来的经过了的总秒数。 11 | 12 | epoch被称为UNIX纪元。 -------------------------------------------------------------------------------- /docs/uname.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | int uname(struct utsname *buf); 6 | ``` 7 | ##参数 8 | 该函数的参数是用来返回的,即声明一个结构体[utsname](#utsname)类型的变量,然后放入函数中。待uname()执行完毕后,会将系统内核信息返回到这个结构体[utsname](#utsname)变量中。 9 | ##返回值 10 | 成功返回0,失败返回-1,并设置errno。 11 | 12 | ---------- 13 | ##utsname 14 | ```c 15 | struct utsname { 16 | char sysname[]; /* 操作系统名称 (如, "Linux") */ 17 | char nodename[]; /* Name within "some implementation-defined 18 | network" */ 19 | char release[]; /* 操作系统发行版本 (如, "2.6.28") */ 20 | char version[]; /* 操作系统版本 */ 21 | char machine[]; /* 硬件标识符 */ 22 | #ifdef _GNU_SOURCE 23 | char domainname[]; /* NIS 或 YP 域名 */ 24 | #endif 25 | }; 26 | ``` -------------------------------------------------------------------------------- /docs/vfork.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | pid_t vfork(void); 7 | ``` 8 | ##描述 9 | 同样是创建子进程,其效率比fork()要快。两者区别有: 10 | - vfork()不会创建并复制父进程的地址空间,而是和父进程共享 11 | - vfork()会阻塞父进程,只运行子进程运行 12 | - 当子进程调用exec()或_exit()时,内核返回地址空间给父进程并唤醒它 13 | 14 | -------------------------------------------------------------------------------- /docs/wait.md: -------------------------------------------------------------------------------- 1 | ###函数原型 2 | ```c 3 | #include 4 | #include 5 | 6 | pid_t wait(int *status); 7 | ``` 8 | ###返回值 9 | |-1 |错误| 10 | |---|---| 11 | |其他|被终止的子进程的id| 12 | ####错误类型 13 | 错误时,系统记录的错误代码**errno**,有两种: 14 | 15 | |ECHILD|没有子进程| 16 | |---|---| 17 | |**EINTER**|收到中断信号**signal**,立即返回| 18 | ###检测退出状态的宏 19 | |宏|缩写含义|描述| 20 | |----|-----|---- 21 | |**WIFEXITED**|wait if exited|子进程正常退出时返回真值 22 | |*WEXITSTATUS*|wait exit status|当上面宏为真时,返回子进程正常退出时状态 23 | |**WIFSIGNALED**|wait if signaled|子进程由于信号导致终止,返回真值 24 | |*WTERMSIG*|wait terminate signal|当上面宏为真时,返回终止子进程的信号类型 25 | |**WIFSTOPPED**|wait if stopped| 26 | |*WSTOPSIG*|wait stop signal| 27 | |**WIFCONTINUED**|wait if continued| 28 | 上表记忆方式为3+1,三对加一单 29 | >另外有书中提及**WCOREDUMP**,即wait core dump(核心转储),不过man手册中未提及此宏 -------------------------------------------------------------------------------- /docs/write.md: -------------------------------------------------------------------------------- 1 | ##函数原型 2 | ```c 3 | #include 4 | 5 | ssize_t write(int fd, const void *buf, size_t count); 6 | ``` 7 | ##参数 8 | 参数同read函数 9 | 10 | |参数|描述| 11 | |:---:|----| 12 | |fd|文件描述符| 13 | |buf|读取的数据存放在buf指针指向的缓冲区| 14 | |count|读取的字节数| 15 | ##返回值 16 | 如果函数调用成功,返回值为写入的**字节数**;否则返回值为**-1**,并设置相应的errno值。 -------------------------------------------------------------------------------- /docs/主机.md: -------------------------------------------------------------------------------- 1 | UNIX系统内部用一个主机网络地址数据库来记住主机名和IP地址直接的映射,这一数据库由文件**/etc/hosts/**或DNS提供。 2 | ##关键头文件 3 | netdb.h 4 | ##关键结构体 5 | ##hostent 6 | 用于报错一台主机的完整地址信息 7 | ```c 8 | struct hostent //host entry的缩写 9 | { 10 | char *h_name; /* 主机的正式名字 */ 11 | char **h_aliases; /* 主机的可选别名 */ 12 | int h_addrtype; /* 主机地址类型 */ 13 | int h_length; /* 每一个地址的长度,以字节为单位 */ 14 | char **h_addr_list; /* 指向主机网络地址数组的指针 */ 15 | } 16 | ``` 17 | ###部分字段解释 18 | |字段名|描述| 19 | |-----|-----| 20 | |h_aliases|它是一个以空结尾的字符串向量 21 | |h_addrtype|它的值是AF_INET或AF_INET6,也可以是其他类型 22 | |h_length|对于IPv4,其值为4,对于IPv6,其值为16 23 | |h_addr_list|主机可能与多个网络连接,因而每一个网络有不同的地址,地址数组以空指针表示结束 24 | ##主要函数 25 | |函数|描述 26 | |----|---- 27 | |[[gethostbyname|gethostbyname]]|通过域名或数-点或冒号形式的IP地址来返回主机信息 28 | |[[gethostbyaddr|gethostbyaddr]]|通过地址结构(如in_addr)返回主机信息 29 | |[[sethostent|sethostent]]|打开主机地址数据库 30 | |[[gethostent|gethostent]]|逐一扫描主机地址数据库登记项 31 | |[[endhostent|endhostent]]|关闭主机地址数据库 -------------------------------------------------------------------------------- /docs/互斥锁.md: -------------------------------------------------------------------------------- 1 | ###类型 2 | *pthread_mutex_t* 3 | ###互斥锁基本操作 4 | |函数|描述 5 | |----|--- 6 | |[[pthread_mutex_init|pthread_mutex_init]]|初始化互斥锁 7 | |[[pthread_mutex_lock|pthread_mutex_lock]]|阻塞申请互斥锁 8 | |[[pthread_mutex_unlock|pthread_mutex_unlock]]|释放互斥锁 9 | |[[pthread_mutex_trylock|pthread_mutex_trylock]]|非阻塞申请互斥锁 10 | |[[pthread_mutex_destroy|pthread_mutex_destroy]]|销毁互斥锁 11 | 12 | ###互斥锁属性的基本操作 13 | |函数|描述 14 | |----|--- 15 | |[[pthread_mutexattr_init|pthread_mutexattr_init]]|初始化属性对象 16 | |[[pthread_mutexattr_destroy|pthread_mutexattr_destroy]]|销毁属性对象 17 | |[[pthread_mutexattr_settype|pthread_mutexattr_settype]]|设置属性对象的属性 18 | |[[pthread_mutexattr_gettype|pthread_mutexattr_gettype]]|获得属性对象的属性 19 | -------------------------------------------------------------------------------- /docs/信号处理.md: -------------------------------------------------------------------------------- 1 | ##信号 2 | 信号是一种进程间通信(IPC)机制,主要用于处理异步事件。 3 | >不同的Unix衍生版所支持的信号类型并不完全相同。除了支持**POSIX**规定的信号外,还支持其他信号。 4 | 5 | ##术语解释 6 | |术语|解释| 7 | |-----|------- 8 | |生成信号|发生了一个需要引起进程注意的事件而导致信号出现时。也叫发送信号 9 | |信号交付|被发送信号的那个进程识别到了信号并采取了适当动作。也叫接收信号 10 | |信号句柄|当信号出现时调用进行专门处理的函数。这个函数称为捕获函数或信号句柄 11 | |信号捕获|若信号交付时进程执行信号句柄,称进程捕获了信号 12 | |悬挂信号|当一个信号已经生成,但还未交付时,称该信号是悬挂的 13 | 14 | ##信号类型 15 | Linux支持62个信号。可以通过在终端输入`kill -l`或`man 7 signal`来查看。本页附录也有记录。 16 | 17 | 信号的宏定义和编号都定义在**signal.h**中。 18 | ##信号产生 19 | 信号的产生方式多种多样,主要有3种: 20 | * 程序错误 21 | * 程序异常,如零做除数 22 | * 进程超越CPU或文件大小的限制 23 | * 外部事件 24 | * 通过键盘终端 25 | * 显示请求 26 | * kill命令(或函数) 27 | 28 | ###通过键盘终端 29 | |组合键|信号| 30 | |-----|----| 31 | |Ctrl+C|SIGINT| 32 | |Ctrl+\\|SIGQUIT| 33 | |Ctrl+Z|SIGSTOP| 34 | ###通过kill命令 35 | ```bash 36 | kill -信号编号 进程号 #比如 kill -15 4264 37 | kill -信号的宏定义 进城号 #比如 kill -SIGTERM 4264 38 | ``` 39 | ###调用系统函数 40 | * [[kill|kill]] 41 | * [[raise|raise]] 42 | * [[alarm|alarm]] 43 | * [[abort|abort]] 44 | 45 | ##信号处理 46 | 主要有3种: 47 | 48 | 1. 忽略信号,对该信号不做处理,进程继续执行。但**SIGKILL**和**SIGSTOP**不能忽略 49 | 2. 捕捉信号,使进程执行指定的程序代 50 | 3. 默认处理方法,系统为每一个信号都设置了默认处理方法,通常为终止进程: 51 | * 流产 52 | * 终止 53 | * 忽略 54 | * 挂起 55 | * 继续 56 | 57 | >还有其他的一些处理方法,比如将信号挂起,不影响当前程序的执行,待需要时再处理该信号。 58 | 59 | 60 | ----------- 61 | -------------------------------------------------------------------------------- /docs/信号类型.md: -------------------------------------------------------------------------------- 1 | **Linux常用31个信号(1~31)**。signal.h中有个常量**NSIG**定义了信号的个数,其值通常为为64。 2 | 3 | |编号|信号|编号|信号|编号|信号| 4 | |----|----|----|----|----|----| 5 | |1|SIGHUP |2|SIGINT |3|SIGQUIT 6 | |4|SIGILL |5|SIGTRAP |6|SIGABRT 7 | |7|SIGBUS |8|SIGFPE |9|SIGKILL 8 | |10|SIGUSR1 |11|SIGSEGV |12|SIGUSR2 9 | |13|SIGPIPE |14|SIGALRM |15|SIGTERM 10 | |16|SIGSTKFLT |17|SIGCHLD |18|SIGCONT 11 | |19|SIGSTOP |20|SIGTSTP |21|SIGTTIN 12 | |22|SIGTTOU |23|SIGURG |24|SIGXCPU 13 | |25|SIGXFSZ |26|SIGVTALRM |27|SIGPROF 14 | |28|SIGWINCH |29|SIGIO |30|SIGPWR 15 | |31|SIGSYS 16 | 这31个信号传统UNIX支持的信号,后来又扩充了一些信号(实时UNIX系统支持的信号)见**附录** 17 | ##分类 18 | ###程序错误类信号 19 | ###程序终止类信号 20 | - SIGHUP 21 | - SIGINT(^C)中断。不产生core文件 22 | - SIGKILL 23 | - SIGQUIT(^\)结束。会产生核心转储的core文件 24 | - SIGTERM 25 | 26 | ###闹钟类信号 27 | ###IO类信号 28 | ###作业控制类信号 29 | - [x] **SIGCHLD**:进程终止时,会向其父进程发送该信号。此信号默认动作是忽略。如果父进程想要在子进程状态发生改变时得到通知,就必须捕获此信号 30 | 31 | ###操作错误类信号 32 | ###其他信号 33 | SIGUSR1和SIGUSR2这两个信号是专门留给用户应用程序自己定义使用的,默认动作是终止进程。 34 | 35 | 36 | 37 | ##附录 38 | |编号|信号|编号|信号|编号|信号| 39 | |----|----|----|----|----|----| 40 | |34|SIGRTMIN |35|SIGRTMIN+1 |36|SIGRTMIN+2 41 | |37|SIGRTMIN+3 |38|SIGRTMIN+4 |39|SIGRTMIN+5 42 | |40|SIGRTMIN+6 |41|SIGRTMIN+7 |42|SIGRTMIN+8 43 | |43|SIGRTMIN+9 |44|SIGRTMIN+10 |45|SIGRTMIN+11 44 | |46|SIGRTMIN+12 |47|SIGRTMIN+13 |48|SIGRTMIN+14 45 | |49|SIGRTMIN+15 |50|SIGRTMAX-14 |51|SIGRTMAX-13 46 | |52|SIGRTMAX-12 |53|SIGRTMAX-11 |54|SIGRTMAX-10 47 | |55|SIGRTMAX-9 |56|SIGRTMAX-8 |57|SIGRTMAX-7 48 | |58|SIGRTMAX-6 |59|SIGRTMAX-5 |60|SIGRTMAX-4 49 | |61|SIGRTMAX-3 |62|SIGRTMAX-2 |63|SIGRTMAX-1 50 | |64|SIGRTMAX 51 | >31和34之间是没有32和33的。前面31个信号1(1~31)是不可靠信号(非实时的),扩充的31个信号(34~64)称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会 -------------------------------------------------------------------------------- /docs/信号量.md: -------------------------------------------------------------------------------- 1 | 原理 2 | ----- 3 | 信号量通信机制主要实现进程间同步,信号量值用来标识系统可用资源的个数。 4 | 实际应用中,两个进程间通信可能会使用多个信号量,因此Linux在管理时以信号量集合的概念来管理。 5 | 通常所说的创建一个信号量实际上是创建了一个信号量的集合。整个信号量集合由以下部分组成: 6 | * 信号量集合数据结构:在此结构中定义了整个信号量集合的基本属性,如访问权限。 7 | * 信号量:信号量集合使用指针指向一个由数组组成的信号量单元,在此信号量单元中存储了创建时申请的信号量。 8 | 9 | 数据结构和共用体 10 | ---------- 11 | ###semid_ds 12 | 信号量集合数据结构。一般不直接调用,而是作为[[semctl()|semctl]]的第四个参数semun的成员出现。 13 | ```c 14 | /*位于/usr/include/linux*/ 15 | struct semid_ds { 16 | struct ipc_perm sem_perm; /* 权限 .. see ipc.h */ 17 | __kernel_time_t sem_otime; /* 最近semop时间 */ 18 | __kernel_time_t sem_ctime; /*最近 修改时间*/ 19 | struct sem *sem_base; /* 队列第一个信号量 */ 20 | struct sem_queue *sem_pending; /* 阻塞信号量 */ 21 | struct sem_queue **sem_pending_last; /* 最后一个阻塞信号量*/ 22 | struct sem_undo *undo; /* undo队列 */ 23 | unsigned short sem_nsems; /* no. of semaphores in array */ 24 | }; 25 | ``` 26 | ###sem 27 | 每个信号量的数据结构 28 | ```c 29 | /*位置不明。。*/ 30 | struct sem{ 31 | int semval; /*信号量的值*/ 32 | int sempid; /*最近一个操作的进程号PID*/ 33 | }; 34 | ``` 35 | ###sembuf 36 | 被[[semop()|semop]]用到 37 | ```c 38 | struct sembuf{ 39 | unsigned short sem_num; /* 信号量标号 */ 40 | short sem_op; /* 信号量操作(加减) */ 41 | short sem_flg; /* 操作标识 */ 42 | }; 43 | ``` 44 | ###semun 45 | 这个是个union类型。注意它包含了几个不同类型的成员,具体用到哪个依据[[semctl()|semctl]]第三个参数的不同而不同。 46 | ```c 47 | union semun { 48 | int val; /* SETVAL的值 */ 49 | struct semid_ds *buf; /* IPC_STAT, IPC_SET的缓冲 */ 50 | unsigned short *array; /* GETALL, SETALL的数组 */ 51 | struct seminfo *__buf; /* IPC_INFO的缓冲(Linux-specific) */ 52 | }; 53 | ``` 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/信号阻塞.md: -------------------------------------------------------------------------------- 1 | 阻塞信号是保持该信号并推迟发送,直到阻塞解除,但不会丢失。 2 | ##结构体sigset_t(信号集合) 3 | 其中每一位对应系统支持的一种信号。结构体内部是数组。 4 | ##函数 5 | |函数名|描述| 6 | |-----|---- 7 | |[[sigemptyset|sigempty]]|初始化信号集为空集 8 | |[[sigfillset|sigfillset]]|初始化信号集包含全部信号 9 | |[[sigaddset|sigaddset]]|向信号集中添加信号 10 | |[[sigdelset|sigdelset]]|从信号集中删除信号 11 | |[[sigismember|sigismember]]|测试某信号是否在信号集中 12 | |[[sigprocmask|sigprocmask]]|使信号集中的信号被屏蔽掉 13 | |[[sigpending|sigpending]]|返回当前进程因受阻而未交付的信号集 14 | 15 | 注意前面四个函数只对信号集类型(sigset_t)变量进行改动,但是并不实际阻塞信号。 16 | 程序在使用sigset_t类型的数据对象之前,必须要调用sigemptyset()或sigfillset()这两个函数之一。 -------------------------------------------------------------------------------- /docs/值-结果参数.md: -------------------------------------------------------------------------------- 1 | ##值-结果参数 2 | 以下函数都需要传递套接字地址结构的指针,并且将结构的大小作为参数传递。不同之处是: 3 | - **从进程到内核**的函数中,结构的大小是以**值**的形式传递的,称为**值参数** 4 | - **从内核到进程**的函数中,结构的大小是以**指针**的形式传递的,称为**结果参数** 5 | 6 | |值参数|结果参数| 7 | |-----|------ 8 | |[[bind|bind]]| 9 | |[[connect|connect]]|[[accept|accept]] 10 | |[[sendto|sendto]]|[[recvfrom|recvfrom]] 11 | ||[[getsockname|getsockname]] 12 | ||[[getpeername|getpeername]] 13 | 14 | 上面位于同一行的的函数,可以认为是对应的一对函数。 -------------------------------------------------------------------------------- /docs/共享内存.md: -------------------------------------------------------------------------------- 1 | 共享内存用于实现进程间大量的数据传输。 2 | 共享内存空间是在内存中单独开辟的一段内存空间。这段空间有自己特有的数据结构,包括访问权限、大小和最近访问时间等。 3 | ##重要的数据结构 4 | ###shmid_ds 5 | ```c 6 | /*位于/usr/include/linux/shm.h*/ 7 | struct shmid_ds { 8 | struct ipc_perm shm_perm; /* 操作权限 */ 9 | int shm_segsz; /* 段大小(bytes) */ 10 | __kernel_time_t shm_atime; /* 最近attach时间 */ 11 | __kernel_time_t shm_dtime; /* 最近detach时间 */ 12 | __kernel_time_t shm_ctime; /* 最近change时间 */ 13 | __kernel_ipc_pid_t shm_cpid; /* 创建者pid */ 14 | __kernel_ipc_pid_t shm_lpid; /* 最近操作者pid */ 15 | unsigned short shm_nattch; /* no. of current attaches */ 16 | unsigned short shm_unused; /* compatibility */ 17 | void *shm_unused2; /* ditto - used by DIPC */ 18 | void *shm_unused3; /* unused */ 19 | }; 20 | ``` 21 | 22 | ------------------------ 23 | ##配合信号量使用 24 | 一般,不允许几个进程同时对共享内存进行写操作。因此有必要使用二元信号量来同步两个进程以实现对共享内存的写操作。 25 | ##与管道的对比 26 | 使用管道(pipe或FIFO)从一个文件传输信息到另一个文件需要复制4次: 27 | * 服务端将信息从输入文件复制到server临时缓存区 28 | * 从server临时缓冲区复制到管道 29 | * 客户端从管道复制到client临时缓冲区 30 | * 再从client临时缓存区复制到输出文件 31 | 32 | 使用共享内存只需要复制两次: 33 | * 从服务端将信息从输入文件复制到共享内存 34 | * 客户端从共享内存复制到输出文件 35 | 36 | >pipe管道中,输入、输出文件对应的是标准输入、输出。 -------------------------------------------------------------------------------- /docs/地址转换函数.md: -------------------------------------------------------------------------------- 1 | 因特网程序使用**inet_aton**、**inet_addr**(已废弃)和**inet_ntoa**函数实现IP地址和点分十进制串之间的转换。 2 | ##函数原型 3 | ```c 4 | #include 5 | 6 | /*将一个点分十进制串转换位网络字节顺序的IP地址,字符串有效返回1,否则为0*/ 7 | int inet_aton(const char *cp,struct in_addr *inp); 8 | 9 | /*若字符串有效则返回32位二进制网络序IPv4地址,否则为INADDR_NONE*/ 10 | in_addr_t inet_addr(const char *cp); 11 | /*将一个网络字节顺序的IP地址转换位它所对应的点分十进制串*/ 12 | char *inet_ntoa(struct in_addr in); 13 | ``` 14 | >缩写释义 15 | arpa貌似是ARPANEAT(阿帕网)的缩写。 16 | n表示network(网络)或numeric(数值) 17 | a表示application(应用) 18 | 19 | inet_addr存在一些问题,所以已被废弃。新的代码都改用inet_aton函数来代替。 20 | ##参数 21 | 注意,**函数中的参数都是地址(in_addr)而不是套接字地址结构! ** 22 | inet_aton和inet_nota两个函数的参数中都有32位二进制网络序IPv4地址。不同的是: 23 | * inet_aton的参数的是指向in_addr结构的指针。(因为这是要返回的) 24 | * 而inet_ntoa的参数是in_addr结构本身。(因为这个是要传入的) 25 | 26 | ------------- 27 | 随着IPv6的出现,产生了两个新的函数:inet_pton和inet_ntop。它们对于IPv4和IPv6都适用。 28 | 名称中的: 29 | - n表示numeric(数值) 30 | - p表示presentation(表达) 31 | 32 | 完成从**数值类型**到**表达格式**之间的转换。所谓表达格式就是IPv4中的点分十进制;IPv6中的冒号分十六进制。 33 | ##函数原型 34 | ```c 35 | #include 36 | 37 | int inet_pton(int af, const char *strptr, void *addrptr); 38 | const char *inet_ntop(int af, const void *addrptr, 39 | char *strptr, socklen_t len); 40 | ``` 41 | ##参数 42 | `void *ddrptr`,即地址结构(in_addr或in6_addr) 43 | 和前面讨论的三个函数相比,这两个函数的参数中的地址均是**指针**(inet_aton参数中地址的是指针,但inet_ntoa参数中的地址是结构本身) 44 | 45 | `char *strptr`,就是要传入或返回的表达格式。**它不可以是一个空指针。** 46 | 47 | len实际是size_t类型,它的值可以使用以下两个宏: 48 | ```c 49 | #define INET_ADDRSTRLEN 16 /* IPv4 */ 50 | #define INET6_ADDRSTRLEN 46 /* IPv6 */ 51 | ``` -------------------------------------------------------------------------------- /docs/套接字函数.md: -------------------------------------------------------------------------------- 1 | 2 | |函数|描述 3 | |----|---- 4 | |[[socket|socket]]|创建一个套接字描述符 5 | |[[socketpair|socketpair]]|创建一个套接字偶对 6 | |[[shutdown|shutdown]]|断开套接字连接 7 | |[[close|close]]|销毁套接字 8 | 9 | ##套接字选项 10 | |函数|描述 11 | |----|----- 12 | |[[getsockopt|sockopt]] 13 | |[[setsockopt|sockopt]] 14 | 适用于流式套接字和数据报套接字 15 | ##流套接字 16 | 通信双方称为**对等**套接字,请求连接的客户端套接字称为**主动**套接字,等待连接的服务端套接字为**被动**套接字。 17 | >一个套接字开始时是主动的,在调用了listen()之后才变成被动的。只有主动套接字才可以用于connect(),只有被动套接字才可以用accept()。 18 | 19 | |函数|描述 20 | |----|----- 21 | |[[bind|bind]]|允许服务进程给予套接字一个地址并建立连接的一方 22 | |[[connect|connect]]|客户进程调用。完成三次握手 23 | |[[accept|accept]]|客户进程完成connect()后,服务进程用该函数完成连接 24 | |[[listen|listen]]|创建一个保存连接请求的侦听队列 25 | |[[getsockname|getsockname]]|连接建立后,获取本地套接字地址 26 | |[[getpeername|getpeername]]|连接建立后,获取与本地套接字连接的对等套接字地址 27 | |[[send|send]]|向已连接的套接字发送数据 28 | |[[recv|recv|]]|从已连接的套接字接收数据 29 | 30 | 31 | ##数据报套接字 32 | |函数|描述 33 | |----|----- 34 | |[[recvfrom|recvfrom]]|接收数据报 35 | |[[sendto|sendto]]|发送数据报 36 | 37 | recvfrom和sendto也可以用于流式套接字,但是很少这样用 38 | 39 | ----------- 40 | -------------------------------------------------------------------------------- /docs/套接字结构.md: -------------------------------------------------------------------------------- 1 | ##套接字地址结构 2 | |地址结构|说明| 3 | |-----|----- 4 | |[sockaddr_un](#sockaddr_un)|UNIX通信域套接字地址 5 | |[sockaddr_in](#sockaddr_in)|IPv4套接字地址 6 | |[sockaddr_in6](#sockaddr_in6)|IPv6套接字地址 7 | ####sockddr_un 8 | ```c 9 | struct sockaddr_un 10 | { 11 | sa_familly_t sun_family; 12 | char sun_path[]; 13 | } 14 | ``` 15 | ####sockaddr_in 16 | ```c 17 | /* 在头文件中定义 */ 18 | struct in_addr 19 | { 20 | in_addr_t s_addr; 21 | }; 22 | struct sockaddr_in 23 | { 24 | uint8_t sin_len; /* POSIX不要求这个字段,它是OSI协议中新增的 */ 25 | sa_family_t sin_family; 26 | in_port_t sin_port; 27 | struct in_addr sin_addr; 28 | char sin_zero[8]; /* 未使用 */ 29 | }; 30 | ``` 31 | 套接字地址结构的每个成员都是以**sin_**开头的。表示的就是socket internet。 32 | * sin_family地址族字段:IPv4为**AF_INET** 33 | * sin_zero这个字段一般置为0。 34 | 35 | ####数据类型 36 | |数据类型|头文件|说明 37 | |-----|:---:|---- 38 | |sa_family_t|``| 39 | |socklen_t|``|uint32_t 40 | |in_addr_t|``|IPV4地址uin32_t 41 | |in_port_t|``|端口uint16_t 42 | 43 | 由于历史原因,地址类型(in_addr)定义成了矢量(即结构体),实际上因为其只包含一个字段,完全可以用标量来表示。 44 | >节选自《UNP》的解释 45 | >>早期版本(4.2BSD)把in_addr定义为多种结构的联合,允许访问一个32为IPv4地址的所有4个字节,或者2个16位值。在IP地址划分为A、B、C类的时期,便于获取地址中的适当字节(比如单独获取网络号或主机号)。然后随着子网划分技术的来临和五分类编址(CIDR)的出现,各种地址类正在消失。那个联合已经不再需要了。 46 | 不难理解,IPv4的地址是32位,端口是16位(端口号取值范围0~65535) 47 | 48 | ####sockaddr_in6 49 | ```c 50 | struct in6_addr 51 | { 52 | uint8_t s6_addr[16]; /* IPv6地址是128位(8×16) */ 53 | }; 54 | #define SIN6_LEN /* 用于编译时测试 */ 55 | struct sockaddr_in6 56 | { 57 | uint8_t sin6_len; 58 | sa_family_t sin6_family; 59 | in_port_t sin6_port; 60 | 61 | uint32_t sin6_flowinfo; 62 | struct in6_addr sin6_addr; 63 | 64 | uint32_t sin6_scope_id; 65 | }; 66 | ``` 67 | sin6_family为地址族字段:IPv6为AF_INET6 68 | -------------------------------------------------------------------------------- /docs/字节序转换函数.md: -------------------------------------------------------------------------------- 1 | ##字节序 2 | * 大端:起始地址存储高序字节 3 | * 小端:起始地址存储低序字节 4 | 5 | 网络协议都使用**网络字节序**(大端)。主机上的字节序称为**主机字节序**(有的系统采用大端,有的系统采用小端) 6 | 7 | ##字节序转换函数函数原型 8 | ```c 9 | /* 有些系统中#include */ 10 | #include 11 | 12 | uint16_t htons(uint16_t host16bitvalue); 13 | uint32_t htonl(uint32_t host32bitvalue); 14 | 15 | uint16_t ntohs(uint16_t net16bitvalue); 16 | uint32_t ntohl(uint32_t net32bitvalue); 17 | ``` 18 | 函数名中 19 | * h:host(主机序) 20 | * n:net(网络序) 21 | * s:short类型。16位 22 | * l:long类型。32位。*有的系统(如Digital Alpha)尽管long是64位,但htonl和ntohl返回的仍然是32位值* 23 | 24 | 上面四个函数,进行主机序和网络序之间16和32位的转换。即IP地址和端口号的转换。 -------------------------------------------------------------------------------- /docs/带外数据.md: -------------------------------------------------------------------------------- 1 | 带外数据即简称**OOB**(out-of-band) 2 | 3 | 带外数据是流式套接字独有的。当出现紧急情况时,无法立即通知接收进程。带外数据正用于解决这一问题。带外数据在正常的数据流之外发送,其效果相当于越过套接字上所有等待数据。当它到达接收进程时,接收进程会收到一个信号,从而进程可以立即处理这个数据。 4 | ##带外数据的发送 5 | 比较简单,只需用MSG_OOB标志调用[[send()|send]]即可 6 | ##带外数据的接收 7 | 有两种方式: 8 | - 使用信号 9 | - 使用[[select()|select]] 10 | 11 | 发送程序发送的每一个带外数据对接收程序都生成了一个**SIGURG**信号。接收者收到带外数据的时机是不确定的。 12 | 13 | ##带外数据标志 14 | ``` 15 | 带外数据如果没有设置**SO_OOBINLINE**选项,即没有**嵌入**到普通数据之中,那么在收到带外数据通知后直接调用recv()就能读带外数据。但如果设置了这个选项,使带外数据嵌入到了普通数据之中我们要怎么读带外数据呢? 16 | ``` 17 | 流套接字在接收带外数据时会自动放置一标志于正常数据流中。这个标志指出带外数据发送时原来所在的位置。带外数据标志用来区分哪些数据位于带外数据之前,哪些数据位于带外数据之后。 18 | 需要用[[sockatmark()|sockatmart]]来读带外数据 -------------------------------------------------------------------------------- /docs/文件I-O.md: -------------------------------------------------------------------------------- 1 | ##文件I/O方式分为`两`种: 2 | * 基于文件描述符的I/O操作(Linux系统API) 3 | * 基于数据流的I/O操作(标准C) 4 | 5 | ##基于文件描述符 6 | 基于文件描述符的I/O常用的就是`5`个系统函数: 7 | 8 | |[open][1]|[read][2]|[write][3]|[lseek][4]|[close][5] 9 | |----|----|-----|-----|----- 10 | 11 | ***** 12 | [1]:open 13 | [2]:read 14 | [3]:write 15 | ##基于数据流 16 | 基于数据流的I/O操作常用的函数有: 17 | 18 | |fopen|fclose|fread|fscanf|fwrite|getc 19 | |-----|------|-----|------|-----|----- 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/文件操作.md: -------------------------------------------------------------------------------- 1 | Linux和各种Unix-like系统中有一重要概念————*万物皆文件* 2 | ##分类 3 | - [x] 根据处理方法的不同,分为: 4 | * 缓冲区文件 5 | * 非缓冲区文件 6 | - [x] 根据其数据组织形式的不同,分为: 7 | * 文本文件 8 | * 二进制文件 9 | - [x] 根据其存放数据的作用的不同,分为: 10 | * **-** 普通文件(regular) 11 | * **d** 目录文件 12 | * **l** 符号链接文件 13 | * 设备文件 14 | * **b** 块设备文件 15 | * **c** 字符设备文件 16 | * **p** 知名管道文件(FIFO) 17 | * **s** 套接字文件(socket) 18 | 19 | ##索引节点 20 | 索引节点(inode)所包含的信息都封装在结构体stat中: 21 | ```c 22 | struct stat { 23 | dev_t st_dev; /* ID of device containing file */ 24 | ino_t st_ino; /* inode number */ 25 | mode_t st_mode; /* protection */ 26 | nlink_t st_nlink; /* number of hard links */ 27 | uid_t st_uid; /* user ID of owner */ 28 | gid_t st_gid; /* group ID of owner */ 29 | dev_t st_rdev; /* device ID (if special file) */ 30 | off_t st_size; /* total size, in bytes */ 31 | blksize_t st_blksize; /* blocksize for filesystem I/O */ 32 | blkcnt_t st_blocks; /* number of 512B blocks allocated */ 33 | time_t st_atime; /* time of last access */ 34 | time_t st_mtime; /* time of last modification */ 35 | time_t st_ctime; /* time of last status change */ 36 | }; 37 | ``` -------------------------------------------------------------------------------- /docs/时间.md: -------------------------------------------------------------------------------- 1 | ##涉及头文件 2 | - time.h 3 | - sys/time.h 4 | 5 | ##结构体 6 | ###struct timeval 7 | ```c 8 | /* 在头文件中定义 */ 9 | 10 | struct timeval { 11 | time_t tv_sec; /* 秒 */ 12 | suseconds_t tv_usec; /* 微秒 */ 13 | }; 14 | ``` 15 | 实际上结构体成员中的秒和微秒都是`long`类型。 16 | ###struct timespec 17 | ```c 18 | struct timespec { 19 | long tv_sec; /* 秒 */ 20 | long tv_nsec; /* 纳秒 */ 21 | }; 22 | ``` 23 | ###struct tmANSI C 24 | ```c 25 | /* 在头文件中定义 */ 26 | struct tm 27 | { 28 | int tm_sec; /* 秒. [0-60] (1 leap second) */ 29 | int tm_min; /* 分钟. [0-59] */ 30 | int tm_hour; /* 小时. [0-23] */ 31 | int tm_mday; /* 天. [1-31] */ 32 | int tm_mon; /* 月. [0-11] */ 33 | int tm_year; /* 年 - 1900. */ 34 | int tm_wday; /* 每周第几天. [0-6] */ 35 | int tm_yday; /* 每年第几天.[0-365] */ 36 | int tm_isdst; /* DST. [-1/0/1]*/ 37 | ... 38 | }; 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/服务.md: -------------------------------------------------------------------------------- 1 | UNIX系统有一个记录标准服务的数据库,这个数据库由头文件**/etc/services**或域名服务器提供。 2 | ##关键头文件 3 | netdb.h 4 | ##关键结构体 5 | ```c 6 | struct servent /* server entry的缩写 */ 7 | { 8 | char *s_name; /* 服务程序的正式名字 */ 9 | char *s_alises;/* 服务程序的别名,为一字符串数组,空指针标志该数组结束 */ 10 | int s_port; /* 端口号,按网络字节序给出 */ 11 | char *s_proto; /* 与该服务一起使用的协议名 */ 12 | } 13 | ``` 14 | ##主要函数 15 | |函数|描述 16 | |----|------ 17 | |[[getservbyname|getservbyname]]|通过服务名和协议名返回该服务的servent结构 18 | |[[getservbyport|getservbyport]]|通过端口号和协议名返回该服务的servent结构 19 | |[[setservent|setservent]]|打开服务数据库以准备 开始扫描 20 | |[[getservent|getservent]]|返回服务数据库的下一项,如果不再有下一项,则返回空指针 21 | |[[endservent|endservent]]|关闭服务数据库 22 | 23 | -------------------------------------------------------------------------------- /docs/消息队列.md: -------------------------------------------------------------------------------- 1 | 消息队列 2 | ========= 3 | 消息的链式队列。 4 | 重要的数据结构 5 | ##msqid_ds 6 | ```c 7 | //位置/usr/include/linux/msg.h 8 | struct msqid_ds { 9 | struct ipc_perm msg_perm; 10 | struct msg *msg_first; /* 指向消息头 */ 11 | struct msg *msg_last; /* 指向消息尾 */ 12 | __kernel_time_t msg_stime; /* 最近msgsnd(发送消息)时间 */ 13 | __kernel_time_t msg_rtime; /* 最近msgrcv(接收消息)时间 */ 14 | __kernel_time_t msg_ctime; /* 最近修改时间 */ 15 | unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ 16 | unsigned long msg_lqbytes; /* ditto */ 17 | unsigned short msg_cbytes; /* 当前队列的字节数 */ 18 | unsigned short msg_qnum; /* 当前队列中消息个数 */ 19 | unsigned short msg_qbytes; /* 队列最大字节数 */ 20 | __kernel_ipc_pid_t msg_lspid; /* 最近msgsnd的pid */ 21 | __kernel_ipc_pid_t msg_lrpid; /* 最近receive的pid */ 22 | }; 23 | ``` 24 | ##key值与ID值 25 | 每一个IPC机制都有一个ID,只有ID值相同才能传递数据。它的类型是key_t(*int*),但是设置任意数字为key值有违软件设计的思想。所以Linux提供了函数[ftok](ftok)来创建key值,以文件为参数,提高了与文件的关联度。 -------------------------------------------------------------------------------- /docs/目录操作.md: -------------------------------------------------------------------------------- 1 | >目录其本质也是一种文件,它的**r**权限是`ls`,**x**权限是`cd` 2 | 3 | ##DIR结构体 4 | Unix系统为用户提供了一种和文件结构**FILE**类似的目录结构**DIR**。它被称为**目录流**,目录中的**目录项**用dirent结构表示(*但DIR的并非包含dirent成员*) 5 | ###dirent结构 6 | |结构体成员|类型|描述 7 | |----|---|--- 8 | |d_into|ino_t|文件的inode号 9 | |d_name[ ]|char|以NULL结尾的文件名 10 | 11 | ##常用函数(库调用) 12 | |函数名|描述 13 | |----|--- 14 | |[[opendir|opendir]]|根据目录的路径字符串,返回一个DIR指针 15 | |[[readdir|readdir]]|根据DIR指针,返回DIR指针所指向的目录项的指针(dirent *) 16 | |[[closedir|closedir]]|关闭DIR指针所指向的目录流 17 | |[[telldir|telldir]]|返回DIR指针所指向目录流的当前位置(long类型) 18 | |[[seekdir|seekdir]]|将DIR指针所指向的目录流偏移跳跃到某一位置 -------------------------------------------------------------------------------- /docs/系统管理.md: -------------------------------------------------------------------------------- 1 | 2 | ##系统管理 3 | |函数|描述 4 | |----|----- 5 | |[uname](uname.md)|得到内核的名称和信息| 6 | |[getpwuid](getpwuid.md)|通过**uid**获得相应的结构体passwd 7 | |[getpwnam]()|通过**用户名**获得相应的结构体passwd 8 | |[getspnam]()|通过**用户名**获得结构体spwd(内包含密码) 9 | |[getgrgid](getgrgid.md)|通过**gid**获得相应的结构体group 10 | |[getgrnam]()|通过**组名**获得相应的结构体group 11 | |[getenv]()|获取系统环境变量的值 12 | -------------------------------------------------------------------------------- /docs/线程.md: -------------------------------------------------------------------------------- 1 | 线程是进程中的一个独立控制流。一个进程包含一个或多个线程。 2 | 线程基本上不拥有系统资源(只有少量运行中必不可少的资源),但它可与同属于一个进程的其他线程共享该进程的全部资源,包括地址空间(数据段和堆段)、通用信号处理机制、数据与I/O。而线程有自己的栈(自动变量)。 3 | >进程是系统资源分配的最小单位,线程是CPU调度的最小单位 4 | 5 | ##pthread 6 | Linux中的线程相关函数都是以pthread开头的,它的含义是:POSIX thread,即POSIX标准的线程。 7 | 关于POSIX线程的更多概念,大家可以去`man pthreads`查看。 8 | ##API对比 9 | |功能|线程|进程 10 | |---|----|--- 11 | |创建|pthread_create|fork,vfork 12 | |退出|pthread_exit|exit 13 | |等待|pthread_join|wait,waitpid 14 | |取消/终止|pthread_cacel|abort 15 | |读取ID|pthread_self|getpid 16 | |通信机制|信号,信号量,互斥锁,读写锁,条件变量|管道(有名/无名),信号,信号量,消息队列,共享内存 17 | ##调度 18 | 线程和进程支持同样的调度策略: 19 | * SCHED_OTHER 分时调度策略,(默认的) 20 | * SCHED_FIFO 实时调度策略,先到先服务 21 | * SCHED_RR 实时调度策略,时间片轮转 22 | 23 | ##编译 24 | 在编译(**gcc**)包含pthread函数的程序时,要显式地链接线程库,即**-lpthread**。 -------------------------------------------------------------------------------- /docs/线程同步.md: -------------------------------------------------------------------------------- 1 | ##[互斥锁](互斥锁) 2 | ##条件变量 3 | ##POSIX信号量 -------------------------------------------------------------------------------- /docs/网络编程.md: -------------------------------------------------------------------------------- 1 | 网络编程 2 | ======= 3 | Unix/Linux网络编程常用的头文件有: 4 | - arpa/inet.h 5 | - netinet/in.h 6 | - sys/socket.h 7 | - netdb.h 8 | - hostent(结构体)表示主机 9 | - servent(结构体)表示服务数据库的登记项信息 10 | 11 | -------------------------------------------------------------------------------- /docs/进程控制.md: -------------------------------------------------------------------------------- 1 | 进程控制 2 | ======= 3 | ##fork 4 | 新建一个子进程。具有**一次调用,两次返回**的特点。 5 | 6 | ##evecve 7 | 有6种表达: 8 | -------------------------------------------------------------------------------- /docs/进程通信.md: -------------------------------------------------------------------------------- 1 | 进程通信 2 | ======= 3 | 进程间通信(Inter-Process Communication),简称**IPC**。 4 | ##分类 5 | * 管道通信 6 | * 信号通信 7 | * 共享内存通信* 8 | * 信号量通信* 9 | * 消息队列通信* 10 | * 套接口(Socket)通信 11 | * *全双工管道通信*(部分Unix系统支持,Linux只支持半双工管道) 12 | 13 | >加星号*的三种通信方式,是源自于AT&T发行的System V(SYSV)版本的新IPC机制。 14 | 15 | ##管道 16 | * 管道**pipe** 17 | * 命名管道**FIFO** 18 | 19 | ###FIFO 20 | 命名管道FIFO,应该是静态实体,因此创建方式有两种: 21 | * 函数*[mkfifo](./mkfifo)*创建 22 | * 终端使用命令*mknod*,*mkfifo* 创建 23 | 24 | --------------------------- 25 | --------------------------------------------------------------------------------