Linux系统常用命令、标准C库函数和系统调用
目录
一、常用命令
env
echo $name
键=值
export name
unset name
gcc -c xxx.c
ar 命令
ar -r libxxx.a xxx1.o xxx2.o
gcc -c -fpic xxx.c
gcc -shared -fpic xxx1.c xxx2.c -o libxxx.so
kill [-信号] PID
kill -l
软链接:ln -s xxx yyy
硬链接:ln source_file target_link
ls -l 命令查看文件的类型
pstree
ps [...]
ulimit -u
mkfifo myfifo
写入数据到命名管道
从命名管道读取数据
删除命名管道
ifconfig
| 管道符号
ipcs -x
ipcrm -x
二、标准库
#include
int main (int argc, char* argv[], char* envp[])
void perror(char const* tag);
#include
#include
介绍
void* dlopen(char const* filename, int flag);
void* dlsym(void* handle, char const* symbol);
int dlclose(void* handle);
char* dlerror(void);
#include
void exit(int status);
int atexit (void (*function) (void));
int on_exit (void (*function) (int , void*), void* arg);
void _Exit(int status);
void abort(void);
int system (const char* command);
#include
char* strerror(int errnum)
三、系统调用|POSIX
#include
int kill(pid_t pid, int signum);
int raise (int signum);
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
int sigfillset (sigset_t* sigset);
int sigemptyset (sigset_t* sigset);
int sigaddset (sigset_t* sigset, int signum);
int sigdelset (sigset_t* sigset, int signum);
int sigismember (const sigset_t* sigset, int signum);
int sigprocmask (int how, const sigset_t* sigset,sigset_t* oldset);
int sigpending (sigset_t* sigset);
#include
int close(int fd);
ssize_t write(int fd, void const* buf, size_t count);
ssize_t read(int fd, void* buf, size_t count);
void* sbrk(intptr_t increment);
int brk(void* end_data_segment);
off_t lseek(int fd, off_t offset, int whence);
int dup(int oldfd);
int dup2(int oldfd, int newfd);
int access(char const* pathname, int mode);
int truncate(char const* path, off_t length);
int ftruncate(int fd, off_t length);
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
gid_t getgid(void);
uid_t geteuid(void);
gid_t getegid(void);
pid_t fork(void);
void _exit(int status);
int execl (const char* path, const char* arg, ...);族6
int pause(void);
unsigned int sleep(unsigned int seconds);
int usleep (useconds_t usec);
unsigned int alarm(unsigned int seconds);
int pipe(int pipefd[2]);
#include
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void* start, size_t length);
内存映射的建立和解除
#include
int open(char const* pathname, int flags, mode_t mode);
int fcntl(int fd, F_SETLK/F_SETLKW,struct flock* lock);
#include
int stat(char const* path, struct stat* buf);
int lstat(char const* path, struct stat* buf);
int fstat(int fd, struct stat* buf);
int mkfifo(char const* pathname, mode_t mode);
#include
pid_t wait(int* status);
pid_t waitpid(pid_t pid, int* status, int options);
#include
key_t ftok (const char* pathname, int proj_id);
#include
int shmget(key_t key, size_t size, int shmflg);
void* shmat(int shmid, void const* shmaddr, int shmflg);
int shmdt(void const* shmaddr);
int shmctl(int shmid, IPC_RMID, NULL);
#include
int msgget(key_t key, int msgflg);
int msgsnd(int msgid, void const* msgp, size_t msgsz, int msgflg);
int msgrcv(int msgid, void* msgp, size_t msgsz, long msgtyp, int msgflg);
int msgctl(int msgid, IPC_RMID, NULL);
#include
int socket(int domain, int type, int protocol);
int bind(int sockfd, struct sockaddr const* addr, socklen_t addrlen);
int connect(int sockfd, struct sockaddr const* addr, socklen_t addrlen);
字节序转换函数
int listen(int sockfd, int backlog)
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
ssize_t recv(int sockfd, void* buf, size_t count, int flags);
ssize_t send(int sockfd, void const* buf, size_t count, int flags);
lssize_t recvfrom(int sockfd, void* buf, size_t count, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
ssize_t sendto(int sockfd, void const* buf, size_t count, int flags, struct sockaddr const* dest_addr, socklen_t addrlen);
#incluce
struct hostent* gethostbyname(char const* host_name);
#include
int pthread_create(pthread_t* tid, pthread_attr_t const* attr, void* (*start_routine)(void*), void* arg)
int pthread_join(pthread_t tid, void** retval);
int pthread_detach(pthread_t tid);
pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);
int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t const* attr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
int pthread_mutex_lock (pthread_mutex_t* mutex);
int pthread_mutex_unlock (pthread_mutex_t* mutex);
int pthread_cond_init (pthread_cond_t* cond,const pthread_condattr_t* attr);
int pthread_cond_destroy(pthread_cond_t* cond)
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
int pthread_cond_signal(pthread_cond_t* cond);
#include
long int syscall(SYS_gettid);
一、常用命令
env
在终端中直接输入 env
命令,系统会列出当前所有的环境变量及其值。
--help
:显示env
命令的帮助信息。--version
:显示env
命令的版本信息。
echo $name
通过echo $name 可以查看某个(name)环境变量的值。
拓展:
PATH环境变量 :
1、该环境变量所记录的是bash进程对命令的检索路径 格式为“:”分割的多个路径。当在bash下输入命令的时候,首先,在第一个路 径下找该命令的可执行程序,找到就执行,不再向后找;如果找不到,在第 二个路径下找,找到就执行,不再向后找;如果找不到,继续下一个路径。 如果到最后一个路径都找不到,就提示该命令不能找到的错误。
2、对PAHT环境变量进行设置,添加当前路径到环境变量 PATH=$PATH:. 在命令行执行程序即可省略“./”。 ./a.out ---> a.out
3、如果没有特殊操作,对环境变量的设置仅对当前shell进程有效,开启新的 终端,之前的操作不会被保留。
在家目录下有名为.bashrc的脚本文件,每次bash进程启动前,都会执行该 脚本文件的内容。如果希望环境变量的设置对每个bash进程都有效,可以 将环境变量的设置写在该脚本文件中。
执行 source ~/.bashrc 命令,可以使文件立即生效。
键=值
环境变量的添加。
1、在终端窗口输入 FOOD=dumpling ,表示向当前进程中增加名为“FOOD”值 为“dumpling”的环境变量,如果环境变量已经存在,则更改其值。
2、强调! 在“=”左右不要加空格。
3、关闭当前shell后失效。
export name
功能:将局部环境变量设置成全局变量 。name表示要操作的键。
拓展:环境变量分成两大类:
全局环境变量:当前shell和其子进程都是可见的
局部环境变量:只有当前shell可见
unset name
功能:删除环境变量
gcc -c xxx.c
功能:编译成目标文件,尾椎为xxx.o
ar 命令
ar [选项]
-r 将目标插入到静态库中,已存在则更新
-q 将目标文件追加到静态库尾
-d 从静态库中删除目标文件
-t 列表显示静态库中的目标文件
-x 将静态库展开为目标文件
ar -r libxxx.a xxx1.o xxx2.o
功能:打包成静态库
以构建数学库为例,静态库的构建顺序如下:
A. 编辑库的实现代码和接口声明
– 计算模块:calc.h、calc.c
– 显示模块:show.h、show.c
– 接口文件:math.h
B. 编译成目标文件 gcc -c calc.c gcc -c show.c
C. 打包成静态库 ar -r libmath.a calc.o show.o
拓展:静态库的使用
1、编辑库的使用代码
main.c
2、编译并链接静态库
直接链接静态库
gcc main.c libmath.a
用-l指定库名,用-L指定库路径
gcc mian.c -lmath -L.
用-l指定库名,用LIBRARY_PATH环境变量指定库路径
export LIBRARY_PATH=$LIBRARY_PATH:.
gcc main.c -lmath
gcc -c -fpic xxx.c
功能:编译成目标文件,尾椎.o文件
PIC (Position Independent Code,位置无关代码)
调用代码通过相对地址标识调用代码的位置,模块中的指令与该模块被 加载到内存中的位置无关
-fPIC : 大模式,生成代码比较大,运行速度比较慢,所有平台都支持
-fpic : 小模式,生成代码比较小,运行速度比较快,仅部分平台支持
gcc -shared -fpic xxx1.c xxx2.c -o libxxx.so
功能:编译链接合并成一步完成
拓展:
1、动态库的构建:
A. 编辑库的实现代码和接口声明
– 计算模块:calc.h、calc.c
– 显示模块:show.h、show.c
– 接口文件:math.h
B. 编译成目标文件
gcc -c -fpic calc.c gcc -c -fpic show.c
C. 打包成动态库
gcc -shared calc.o show.o -o libmath.so
2、动态库的使用:
编辑库的使用代码
main.c
编译并链接动态库
直接链接动态库
gcc main.c libmath.so
用-l指定库名,用-L指定库路径
gcc mian.c -lmath -L.
用-l指定库名,用LIBRARY_PATH环境变量指定库路径
export LIBRARY_PATH=$LIBRARY_PATH:.
gcc main.c -lmath
3、注意
运行时需要保证LD_LIBRARY_PATH环境变量中包含共享库所在的路径 用以告知链接器在运行时链接动态库 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
在可执行程序的链接阶段,并不将所调用函数的二进制代码复制到可执行程序 中,而只是将该函数在共享库中的地址嵌入到调用模块中,因此运行时需要依 赖共享库
kill [-信号] PID
1、若不指明具体信号,缺省发送SIGTERM(15)信号
2、若要指明具体信号,可以使用信号编号,也可以使用信号名称,而且信号名称中的“SIG” 前缀可以省略不写。例如
• kill -9 1234
• kill -SIGKILL 1234 5678
• kill -KILL -1
3、超级用户可以发给任何进程,而普通用户只能发给自己的进程
kill -l
功能:用于列出系统支持的信号列表的命令
拓展:
kill 命令本身主要用于向进程发送信号,而 kill -l 中的 -l 选项(list 的缩写),就是用来列出所有可用的信号及其对应的名称和编号。
执行 kill -l 命令后,系统会输出一系列信号的名称和编号,通常按照编号从小到大的顺序排列。例如,在常见的 Linux 系统中,输出如下:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
一共有62个信号,其中前31个信号为不可靠的非实时信号,后31个为可靠的实时信号
信号的处理:
忽略:什么也不做,SIGKILL(9)和SIGSTOP(19)不能被忽略
默认:在没有人为设置的情况,系统缺省的处理行为。
捕获:接收到信号的进程会暂停执行,转而执行一段事先编写好的处理代码,执行完毕 后再从暂停执行的地方继续运行。
前31个信号不可靠的非实时信号:
信号编号 | 信号名称 | 默认动作 | 描述 |
---|---|---|---|
1 | SIGHUP | 终止 | 挂起信号,通常在终端连接断开或用户退出登录时发送给相关进程,用于通知进程重新初始化或终止 |
2 | SIGINT | 终止 | 中断信号,当用户在终端按下Ctrl + C 组合键时,系统会向当前正在运行的前台进程发送该信号,用于请求进程中断当前操作并退出 |
3 | SIGQUIT | 核心转储并终止 | 退出信号,用户按下Ctrl + \ 组合键时发送,进程退出时会产生一个核心转储文件(如果系统配置允许) |
4 | SIGILL | 核心转储并终止 | 非法指令信号,当进程执行了一条非法的机器指令时,系统会发送该信号 |
5 | SIGTRAP | 核心转储并终止 | 跟踪陷阱信号,用于调试程序时捕捉进程的特定操作,如断点命中或单步执行 |
6 | SIGABRT | 核心转储并终止 | 异常终止信号,通常由abort 函数调用产生,进程会立即终止并生成核心转储文件 |
7 | SIGBUS | 核心转储并终止 | 总线错误信号,当进程访问了硬件不允许访问的内存地址,或发生硬件相关的错误时发送 |
8 | SIGFPE | 核心转储并终止 | 浮点运算错误信号,当进程进行了非法的浮点运算,如除以零、溢出或无效的操作时,会收到该信号 |
9 | SIGKILL | 终止 | 强制终止信号,用于立即终止进程,并且进程无法忽略该信号 |
10 | SIGUSR1 | 终止 | 用户定义信号 1,可由用户或应用程序自定义使用,用于进程间的特定通信或通知 |
11 | SIGSEGV | 核心转储并终止 | 段错误信号,当进程访问了无效的内存地址,如访问未分配的内存、越界访问数组或使用了空指针时,系统会发送该信号 |
12 | SIGUSR2 | 终止 | 用户定义信号 2,与 SIGUSR1 类似,是另一个可供用户或应用程序自定义使用的信号 |
13 | SIGPIPE | 终止 | 管道破裂信号,当进程向一个已关闭的管道或没有读端的管道写入数据时,会收到该信号 |
14 | SIGALRM | 终止 | 闹钟信号,使用alarm 函数设置定时器,超时后系统向进程发送该信号,用于定时任务或超时处理 |
15 | SIGTERM | 终止 | 终止信号,用于正常终止进程,允许进程进行清理操作后再退出 |
16 | SIGSTKFLT | 终止 | 栈错误信号,通常与协处理器的栈错误相关,在一些特定的硬件或软件环境中使用 |
17 | SIGCHLD | 忽略 | 子进程状态改变信号,当子进程终止、停止或继续运行时,父进程会收到该信号,用于父进程对其子进程的状态监控 |
18 | SIGCONT | 继续执行 | 继续信号,用于让暂停的进程继续执行,通常与作业控制相关 |
19 | SIGSTOP | 停止执行 | 停止信号,用于暂停进程的执行,进程会停止运行但不终止,可通过 SIGCONT 信号恢复 |
20 | SIGTSTP | 停止执行 | 终端停止信号,当用户在终端按下Ctrl + Z 组合键时,系统会向当前正在运行的前台进程发送该信号,将进程暂停并放入后台 |
21 | SIGTTIN | 停止执行 | 后台进程尝试读取终端输入信号,当后台进程试图从终端读取数据时,系统会发送该信号,默认会暂停进程 |
22 | SIGTTOU | 停止执行 | 后台进程尝试写入终端输出信号,当后台进程试图向终端写入数据时,系统会发送该信号,默认会暂停进程 |
23 | SIGURG | 忽略 | 紧急信号,用于表示网络连接上有紧急数据需要处理,通常与套接字相关 |
24 | SIGXCPU | 核心转储并终止 | 超过 CPU 时间限制信号,当进程使用的 CPU 时间超过了系统或用户设置的限制时,系统会发送该信号 |
25 | SIGXFSZ | 核心转储并终止 | 超过文件大小限制信号,当进程试图创建超过系统或用户设置的文件大小限制的文件时,系统会发送该信号 |
26 | SIGVTALRM | 终止 | 虚拟定时器信号,基于进程的虚拟时间(用户态时间)计时,当虚拟定时器超时,系统向进程发送该信号 |
27 | SIGPROF | 终止 | 剖析定时器信号,用于统计进程的执行时间和性能分析,基于进程的实际运行时间(包括用户态和内核态时间)计时 |
28 | SIGWINCH | 忽略 | 窗口大小改变信号,当终端窗口的大小发生改变时,系统会向相关进程发送该信号,进程可以根据此信号调整自身的显示或布局 |
29 | SIGIO | 终止 | 异步 I/O 信号,用于通知进程有 I/O 事件发生,可用于实现异步 I/O 操作或事件驱动的编程模型 |
30 | SIGPWR | 终止 | 电源故障信号,当系统检测到电源故障或电源恢复等相关事件时,会发送该信号,用于通知进程进行相应的处理 |
31 | SIGSYS | 核心转储并终止 | 系统调用错误信号,当进程进行了错误的系统调用时,系统会发送该信号,通常表示程序存在错误 |
后31个为可靠的实时信号:
信号编号 | 信号名称 | 默认动作 | 描述 |
---|---|---|---|
34 | SIGRTMIN | 终止 | 实时信号的起始编号,用于应用程序自定义实时信号,具备更高优先级与更精准的传递语义 |
35 | SIGRTMIN + 1 | 终止 | 实时信号,可由用户自定义用途,常用于实时系统中实现特定实时任务或事件通知 |
36 | SIGRTMIN + 2 | 终止 | 实时信号,可用于进程间传递特定实时信息,满足对时间敏感的应用需求 |
37 | SIGRTMIN + 3 | 终止 | 实时信号,例如在多媒体应用中可处理音频或视频的实时同步事件 |
38 | SIGRTMIN + 4 | 终止 | 实时信号,在工业控制系统等对实时性要求高的场景中,可传递关键控制信号 |
39 | SIGRTMIN + 5 | 终止 | 实时信号,可用于实时监控系统,当检测到特定紧急情况时发送该信号触发及时响应 |
40 | SIGRTMIN + 6 | 终止 | 实时信号,在高性能计算应用中,可协调不同计算任务之间的同步和通信 |
41 | SIGRTMIN + 7 | 终止 | 实时信号,如在自动驾驶系统中,可传递与车辆行驶状态相关的实时信息 |
42 | SIGRTMIN + 8 | 终止 | 实时信号,可用于机器人控制等领域,实现对机器人动作的精确控制和实时反馈 |
43 | SIGRTMIN + 9 | 终止 | 实时信号,在航空航天等对安全性和实时性要求极高的领域,可传递关键飞行控制信息 |
44 | SIGRTMIN + 10 | 终止 | 实时信号,可用于金融交易系统,当发生重要交易事件时发送该信号触发及时处理 |
45 | SIGRTMIN + 11 | 终止 | 实时信号,在视频游戏开发中,可处理游戏中的实时事件,如角色碰撞、场景切换等 |
46 | SIGRTMIN + 12 | 终止 | 实时信号,在网络通信中,可处理实时的数据包到达或连接状态变化等事件 |
47 | SIGRTMIN + 13 | 终止 | 实时信号,在智能家居系统中,可传递传感器检测到的实时信息,如温度变化、门窗开关等 |
48 | SIGRTMIN + 14 | 终止 | 实时信号,在智能交通系统中,可传递交通流量、路况等实时信息 |
49 | SIGRTMIN + 15 | 终止 | 实时信号,可用于工业自动化生产线,实现对生产过程的实时监控和调整 |
50 | SIGRTMAX - 15 | 终止 | 实时信号,是实时信号范围内的一个信号,具体用途可由应用程序按需定义 |
51 | SIGRTMAX - 14 | 终止 | 实时信号,可用于实现对时间要求严格的任务调度或事件处理机制 |
52 | SIGRTMAX - 13 | 终止 | 实时信号,例如在实时数据采集系统中,可标记数据采集的特定时刻或事件 |
53 | SIGRTMAX - 12 | 终止 | 实时信号,在分布式系统中,可用于节点之间的实时通信和协调 |
54 | SIGRTMAX - 11 | 终止 | 实时信号,可用于云计算环境,处理与虚拟机管理或资源分配相关的实时事件 |
55 | SIGRTMAX - 10 | 终止 | 实时信号,在大数据处理系统中,可协调不同数据处理阶段的实时同步 |
56 | SIGRTMAX - 9 | 终止 | 实时信号,可用于物联网应用,实现设备之间的实时通信和控制 |
57 | SIGRTMAX - 8 | 终止 | 实时信号,在医疗设备控制系统中,可传递患者生命体征等实时信息 |
58 | SIGRTMAX - 7 | 终止 | 实时信号,可用于智能电网系统,处理电力分配和监控的实时事件 |
59 | SIGRTMAX - 6 | 终止 | 实时信号,在虚拟现实或增强现实应用中,可处理实时的交互事件 |
60 | SIGRTMAX - 5 | 终止 | 实时信号,可用于智能安防系统,当检测到异常情况时发送该信号触发警报和相关处理 |
61 | SIGRTMAX - 4 | 终止 | 实时信号,在智能农业系统中,可传递土壤湿度、气象等实时信息 |
62 | SIGRTMAX - 3 | 终止 | 实时信号,可用于物流管理系统,实现对货物运输状态的实时跟踪和监控 |
63 | SIGRTMAX - 2 | 终止 | 实时信号,在教育技术领域,可处理在线教学中的实时互动事件 |
64 | SIGRTMAX | 终止 | 实时信号的最大编号,与 SIGRTMIN 相对应,标志着实时信号范围的结束 |
软链接:ln -s xxx yyy
ln -s xxx.c yyy.c 是一个在类 Unix 系统(如 Linux、macOS)中使用的命令,用于创建符号链接(也称为软链接)
例如 ln -s source_file target_link,其中 source_file 是源文件,target_link 是要创建的符号链接。
使用 rm 命令删除符号链接,例如 rm yyy.c
硬链接:ln source_file target_link
直接使用 ln 命令,例如 ln source_file target_link,target_link 就是创建出的硬链接。
ls -l 命令查看文件的类型
-:普通文件
d:目录
s:本地套接字
c:字符设备
b:块设备
l:符号链接
p:有名管道
pstree
功能:以树状结构显示当前所有进程关系
ps [...]
ps 以简略方式显示当前用户拥有控制终端的进程信息,也可以配合以下选项:
a - 显示所有用户拥有控制终端的进程信息
x - 也包括没有控制终端的进程
u - 以详尽方式显示
w - 以更大列宽显示
拓展:
进程信息列表
user : 进程的用户ID
PID :进程ID
%CPU :CPU使用率
%MEM :内存使用率
VSZ :占用虚拟内存的大小(KB)
RSS :占用物理内存的大小(KB)
TTY :终端次设备号
STAT :进程状态
• R - 运行,即正在被处理器执行
• S - 可唤醒睡眠,系统中断、获得资源、收到信号,都可唤醒
• D - 不可唤醒睡眠,只能被wake_up系统调用唤醒
• T - 收到SIGSTOP(19)信号进入暂停状态,收到SIGCONT(18)信号后继续运行
• Z - 僵尸,已终止但其终止状态未被回收 • < - 高优先级
• N - 低优先级
• L - 存在被锁定的内存分页
• s - 会话首进程
• l - 多线程化进程
• + - 在前台进程组中
START :进程开始时间
TIME :进程运行时间
COMMAMD :进程启动命令
ulimit -u
ulimit -u 是一个在类 Unix 系统(如 Linux、macOS)中使用的命令,用于显示或设置当前用户可创建的最大进程数限制。
如果想修改当前用户的最大进程数限制,可以在 ulimit -u 后面跟上一个新的数值。例如,要将最大进程数限制设置为 2048,可以使用命令:ulimit -u 2048
mkfifo myfifo
mkfifo myfifo 用于创建一个命名管道(也称为 FIFO)。
mkfifo:这是一个用于创建命名管道的命令。mkfifo 是 make first-in, first-out 的缩写,它的作用是在文件系统中创建一个特殊类型的文件,即命名管道。
myfifo:这是你要创建的命名管道的名称。你可以根据自己的需求为命名管道指定不同的名称。
可以使用 ls -l 命令查看该命名管道的信息
写入数据到命名管道
可以使用 echo
命令将数据写入命名管道,示例命令如下:
echo "Hello, named pipe!" > myfifo
从命名管道读取数据
可以使用 cat 命令从命名管道中读取数据,示例命令如下:
cat myfifo
注意:命名管道是一种阻塞式的通信机制。如果没有进程从管道中读取数据,那么写入数据的进程会一直阻塞,直到有进程开始读取数据。反之,如果没有进程向管道中写入数据,那么读取数据的进程也会一直阻塞,直到有数据被写入。
删除命名管道
当不再需要命名管道时,可以使用 rm
命令将其删除,示例命令如下:
rm myfifo
ifconfig
功能:用于查看和配置网络接口的相关信息。
|
管道符号
功能:管道符号 | 的作用是将前一个命令的输出作为后一个命令的输入。
示例1:ifconfig | grep inet
ifconfig | grep inet 主要用于过滤并显示网络接口相关的 IPv4 地址信息。下面详细解释这个命令组合的工作原理和执行效果:
ifconfig 命令:ifconfig 用于查看和配置网络接口的相关信息。当单独执行 ifconfig 命令时,会输出当前系统中所有网络接口(如以太网接口、无线接口、回环接口等)的详细信息,包括接口名称、状态标志、IP 地址、子网掩码、广播地址、MAC 地址以及接收和发送的数据包统计等。
| 管道符号:在 Unix 命令行中,管道符号 | 的作用是将前一个命令的输出作为后一个命令的输入。也就是说,ifconfig 命令的输出结果会被传递给后面的 grep 命令进行处理。
grep inet 命令:grep 是一个文本过滤工具,用于在输入的文本中搜索指定的字符串,并输出包含该字符串的行。在 grep inet 中,inet 是要搜索的字符串。当 grep 接收到 ifconfig 命令的输出作为输入时,它会逐行检查这些输出内容,只输出包含 inet 字符串的行。
在大多数情况下,包含 inet 字符串的行通常与网络接口的 IPv4 地址相关。执行 ifconfig | grep inet 命令后,输出如下:
inet 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255inet 127.0.0.1 netmask 255.0.0.0
上述输出中,第一行显示的是以太网接口的 IPv4 地址、子网掩码和广播地址,第二行显示的是本地回环接口(lo)的 IPv4 地址和子网掩码。
示例2:ls -l /etc | more
ls -l /etc | more 这个命令组合的主要作用是将 /etc 目录下文件和子目录的详细信息逐页显示出来。由于 /etc 目录通常包含大量的配置文件和子目录,其输出内容可能会很长,使用 more 命令可以避免输出内容快速滚动而无法查看,让用户能够更方便地浏览和查看这些信息。
ipcs -x
功能:查看系统中的IPC对象
ipcs -m (memory, 共享内存)
ipcs -q (message queue,消息队列)
ipcs -s (semphore,信号量集)
ipcs -a (all, 所有的)
ipcrm -x
功能:删除系统中的IPC对象
ipcrm -m 删除共享内存
ipcrm -q 删除消息对列
ipcrm -s 删除信号量集
二、标准库
#include <stdio.h>
int main (int argc, char* argv[], char* envp[])
int argc:表示命令行参数的数量,其中argc的值至少为 1,因为程序名本身会被当作第一个参数。 char* argv[]:这是一个字符串数组,存放着命令行的各个参数。argv[0]为程序名,后续元素依次为命令行传入的参数。
char* envp[]:是一个字符串数组,存储着环境变量。每个元素是一个形如"变量名=值"的字符串。
void perror(char const* tag);
功能:在标准出错设备上打印最近一次函数调用的错误信息
参数:tag 为用户自己制定的提示内容,输出时,会自动在该提示内容和错误信息之 间添加冒号进行分隔。
#include<errno.h>
1、系统于定义的整数类型全局变量errno中存储了最近一次系统调用的错误编号
2、头文件errno.h中包含了对errno全局变量的外部声明和各种错误号的宏定义
Linux查看宏路径:
/usr/include/errno.h
/usr/include/asm-generic/errno.h
/usr/include/asm-generic/errno-base.h
注意: 虽然所有的错误编号都不是零,但是因为在函数执行成功的情况下存储错误编号的全局变 量errno并不被清零,所以不能用该变量的值是否为零作为最近一次函数调用是否成功的 判断条件。正确的做法是,先根据函数的返回值判断其是否出错,在确定出错的前提下, 再根据errno的值判断具体出了什么错。
#include<dlfcn.h>
介绍
1、在程序执行的过程中,开发人员可以动态加载共享库(什么时候用什么时候 加载)
2、在程序中动态加载共享库需要调用一组特殊的函数,它们被声明于一个专门 的头文件中,并在一个独立的库中予以实现。
3、使用这组函数需要包含此头文件,并链接该库
#include
-ldl
4、辅助工具
查看符号表:nm
列出目标文件、可执行程序、静态库、或共享库中的符号 例:nm libmath.a
查看依赖:ldd
查看可执行文件或者共享库所依赖的共享库 例:ldd a.out
4、举例
#include <stdio.h>
#include <dlfcn.h>int main() {// 打开共享库void *handle = dlopen("./libexample.so", RTLD_LAZY);if (!handle) {fprintf(stderr, "dlopen: %s\n", dlerror());return 1;}// 获取共享库中的函数地址typedef void (*HelloFunction)();HelloFunction hello = (HelloFunction)dlsym(handle, "hello");if (!hello) {fprintf(stderr, "dlsym: %s\n", dlerror());dlclose(handle);return 1;}// 调用函数hello();// 关闭共享库dlclose(handle);return 0;
}
void* dlopen(char const* filename, int flag);
功能:将共享库载入内存并获得其访问句柄
参数:filename 动态库路径,若只给文件名不带目录,则根据 LD_LIBRARY_PATH环境变量的值搜索动态库
flag 加载方式,可取以下值:
RTLD_LAZY - 延迟加载,使用动态库中的符号时才真的加载进内存。
RTLD_NOW - 立即加载。
返回值:成功返回动态库的访问句柄,失败返回NULL。
句柄:句柄唯一地标识了系统内核所维护的共享库对象,将作为后续函数调用的参数
void* dlsym(void* handle, char const* symbol);
功能:从已被加载的动态库中获取特定名称的符号地址
参数: handle 动态库访问句柄
symbol 符号名
返回值:成功返回给定符号的地址,失败返回NULL。
该函数所返回的指针为void*类型,需要造型为与实际目标类型相一致的指针, 才能使用。
例如:
int (*p_add)(int,int) = (int (*)(int,int))dlsym(handle,"add");if(!p_add ){fprintf(stderr,"获取地址失败!\n");exit(EXIT_FAILURE);}int sum = p_add(30,20);
int dlclose(void* handle);
功能:从内存中卸载动态库
参数:handle 动态库句柄
返回值:成功返回0,失败返回非0。
所卸载的共享库未必会真的从内存中立即消失,因为其他程序可能还需要使用该库
只有所有使用该库的程序都显示或隐式地卸载了该库,该库所占用的内存空间才会真正得 到释放 无论所卸载的共享库是否真正被释放,传递给dlclose函数的句柄都会在该函数成功返回 后立即失效
char* dlerror(void);
功能:获取在加载、使用和卸载共享库过程中所发生的错误
返回值:有错误则返回指向错误信息字符串的指针,否则返回NULL。
例如:
void* handle = dlopen("libmath.so",RTLD_NOW);if(!handle){fprintf(stderr,"dlopen:%s\n",dlerror() );exit(EXIT_FAILURE);}
#include<stdlib.h>
void exit(int status);
功能:令进程终止
参数:status 进程的退出码,相当于main函数的返回值
注意:该函数不返回
拓展:
1、虽然exit函数的参数和main函数的返回值都是int类型,但只有其中最低数位的字节可被其父进程回收,高三个字节会被忽略,因此在设计进程的退出码时最好不要超过一字节的值域范围。
2、通过return语句终止进程只能在main函数中实现,但是调用exit函数终止进程可以在包括 main函数在内的任何函数中使用。
3、exit函数在终止调用进程之前还会做几件收尾工作
A、调用实现通过atexit或on_exit函数注册的退出处理函数;
B、冲刷并关闭所有仍处于打开状态的标准I/O流;
C、删除所有通过tmpfile函数创建的临时文件;
D、_exit(status);
4、习惯上,还经常使用EXIT_SUCCESS和EXIT_FAILURE两个宏作为调用exit函数的参数,分 别表示成功和失败。它们的值在多数系统中被定义成0和1,但一般建议使用宏,这样做兼容性更好。
int atexit (void (*function) (void));
参数:function 函数指针,指向退出处理函数
返回值:成功返回0,失败返回-1
注意:atexit函数本身并不调用退出处理函数,而只是将function参数所表示的退出处理函数地址,保存(注册)在系统内核的某个地方(进程表项)。待到exit函数被调用或在main函数里执行return语句时,再由系统内核根据这些退出处理函数的地址来调用它们。此过程也称为回调。
int on_exit (void (*function) (int , void*), void* arg);
参数:
function 函数指针,指向退出处理函数。其中第一个参数来自传递给exit函数的status参数或在main函数里执行return语句的返回值,而第二个参数则来自传递给on_exit函数的arg参数。
arg 泛型指针,将作为第二个参数传递给function所指向的退出处理函数。
返回值:成功返回0,失败返回-1。
void _Exit(int status);
参数:status 进程退出码,相当于main函数的返回值。
注意:该函数不返回!
拓展:
_exit在终止调用进程之前也会做几件收尾工作,但与exit函数所做的不同。事实上,exit 函数在做完它那三件收尾工作之后紧接着就会调用_exit函数
A、关闭所有仍处于打开状态的文件描述符
B、将调用进程的所有子进程托付给init进程收养
C、向调用进程的父进程发送SIGCHLD(17)信号
D、令调用进程终止运行,将status的低八位作为退出码保存在其终止状态中
void abort(void);
功能:向调用进程发送SIGABRT(6)信号,该信号默认情况下可使进程结束
注意:无参数,不返回!
int system (const char* command);
功能:执行shell命令
参数:command shell命令行字符串
返回值:成功返回command进程的终止状态,失败返回-1
system函数执行command参数所表示的命令行,并返回命令进程的终止状态
若command参数取NULL,返回非0表示Shell可用,返回0表示Shell不可用
拓展:
1、在system函数内部调用了vfork、exec和waitpid等函数
如果调用vfork或waitpid函数出错,则返回-1
如果调用exec函数出错,则在子进程中执行exit(127)
如果都成功,则返回command进程的终止状态(由waitpid的status参数获得)
2、使用system函数而不用vfork+exec的好处是,system函数针对各种错误和信号都做了必要的处理,而且system是标准库函数,可跨平台使用。
#include<string.h>
char* strerror(int errnum)
功能:将整数形式的错误号转换为有意义的字符串。
参数:errnum 错误号。
返回值:返回与参数错误号对应的描述字符串。
三、系统调用|POSIX
#include <signal.h>
int kill(pid_t pid, int signum);
功能:向指定的进程发送信号。
参数:pid 可以如下取值。
-1 - 向系统中的所有进程发送信号。
>0 - 向特定进程(由pid标识)发送信号。
signum:信号编号,取0可用于检查pid进程是否存在,如不存在kill函数会返回-1, 且errno为ESRCH
返回值:成功(至少发出去一个信号)返回0,失败返回-1。
int raise (int signum);
功能:向调用进程自己发送信号
参数:signum 信号编号
返回值:成功返回0,失败返回非0
kill(getpid(),signum) 等价于该函数
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:设置调用进程针对特定信号的处理方式
参数:
signum 信号编号
handler 信号的处理方式,可以如下取值
SIG_IGN - 忽略
SIG_DFL - 默认
信号处理函数指针 - 捕获
返回值:成功返回原信号处理方式,如果之前未处理过则返回NULL,失败返回 SIG_ERR。
int sigfillset (sigset_t* sigset);
功能:填满信号集,即将信号集的全部信号位置1
参数:sigset 信号集
返回值:成功返回0,失败返回-1
int sigemptyset (sigset_t* sigset);
功能:清空信号集,即将信号集的全部信号位清0
参数:sigset 信号集
返回值:成功返回0,失败返回-1
int sigaddset (sigset_t* sigset, int signum);
功能:加入信号,即将信号集中与指定信号编号对应的信号位置1
参数:sigset 信号集 signum:信号编号
返回值:成功返回0,失败返回-1
int sigdelset (sigset_t* sigset, int signum);
功能:删除信号,即将信号集中与指定信号编号对应的信号位清0
参数:sigset 信号集 signum:信号编号
返回值:成功返回0,失败返回-1
int sigismember (const sigset_t* sigset, int signum);
功能:判断信号集中是否有某信号,即检查信号集中与指定信号编号对应的信号位是否为1
参数:sigset 信号集 signum:信号编号
返回值:有则返回1,没有返回0,失败返回-1
int sigprocmask (int how, const sigset_t* sigset,sigset_t* oldset);
功能:设置调用进程的信号掩码
参数:how:修改信号掩码的方式,可取以下值
SIG_BLOCK - 将sigset中的信号加入当前信号掩码
SIG_UNBLOCK- 从当前信号掩码中删除sigset中的信号
SIG_SETMASK- 把sigset设置成当前信号掩码
sigset:信号集,取NULL则忽略此参数
oldset:输出原信号掩码,取NULL则忽略此参数 返回值:成功返回0,失败返回-1
示例:
sigset_t sigset;sigemptyset (&sigset);sigaddset (&sigset, SIGINT);sigaddset (&sigset, SIGQUIT);sigset_t oldset;if (sigprocmask (SIG_SETMASK, &sigset,&oldset) == -1) {perror ("sigprocmask");exit (EXIT_FAILURE);}
int sigpending (sigset_t* sigset);
功能:获取调用进程的未决信号集
参数:sigset:输出未决信号集
返回值:成功返回0,失败返回-1
示例:
sigset_t sigset;if (sigpending (&sigset) == -1) {perror ("sigpending");
exit (EXIT_FAILURE);
}if (sigismember (&sigset, SIGINT) == 1){printf ("SIGINT信号未决\n");}
#include<unistd.h>
int close(int fd);
功能:关闭处于打开状态的文件描述符
参数:fd 处于打开状态的文件描述符
ssize_t write(int fd, void const* buf, size_t count);
功能:向指定的文件写入数据
参数:fd 文件描述符 buf 内存缓冲区,即要写入的数据 count 期望写入的字节数
返回值:成功返回实际写入的字节数,失败返回-1。
ssize_t read(int fd, void* buf, size_t count);
功能:从指定的文件中读取数据
参数:
fd 文件描述符
buf 内存缓冲区,存读取到的数据
count 期望读取的字节数
返回值:成功返回实际读取的字节数,失败返回-1。
void* sbrk(intptr_t increment);
功能:以相对方式分配和释放虚拟内存
参数:increment 堆内存的字节增量(以字节为单位)
>0 - 分配内存
<0 - 释放内存
=0 - 当前堆尾
返回值:成功返回调用该函数前的堆尾指针,失败返回-1。
int brk(void* end_data_segment);
功能:以绝对方式分配和释放虚拟内存
参数:end_data_segment 堆尾指针的目标位置
> 堆尾指针的原位置 - 分配内存
< 堆尾指针的原位置 - 释放内存
= 堆尾指针的原位置 - 空操作
返回值:成功返回0,失败返回-1。
off_t lseek(int fd, off_t offset, int whence);
功能:人为调整文件读写位置
参数:
fd:文件描述符。
offset: 文件读写位置偏移字节数
whence: offset参数的偏移起点,可以如下取值:
SEEK_SET - 从文件头(首字节)开始
SEEK_CUR - 从当前位置(最后被读写字节的下一个字节)开始
SEEK_END - 从文件尾(最后一个字节的下一个字节)开始
返回值:成功返回调整后的文件读写位置,失败返回-1
int dup(int oldfd);
功能:复制文件描述符表的特定条目到最小可用项:
参数:oldfd:源文件描述符
返回值:成功返回目标文件描述符,失败返回-1
注意:
1、dup函数将oldfd参数所对应的文件描述符表项复制到文件描述符表第一个空 闲项中,同时返回该表项对应的文件描述符。dup函数返回的文件描述符一定 是调用进程当前未使用的最小文件描述符。
2、dup函数只复制文件描述符表项,不复制文件表项和v节点,因此该函数所返 回的文件描述符可以看做是参数文件描述符oldfd的副本,它们标识同一个文件表项。
3、当关闭文件时,即使是由dup函数产生的文件描述符副本,也应该通过close函 数关闭,因为只有当关联于一个文件表项的所有文件描述符都被关闭了,该文件表项 才会被销毁,类似地,也只有当关联于一个v节点的所有文件表项都被销毁了,v节点 才会被从内存中删除,因此从资源合理利用的角度讲,凡是明确不再继续使用的文件 描述符,都应该尽可能及时地用close函数关闭 ldup函数究竟会把oldfd参数所对应的文件描述符表项,复制到文件描述符表的什么 位置,程序员是无法控制的,这完全由调用该函数时文件描述符表的使用情况决定, 因此对该函数的返回值做任何约束性假设都是不严谨的。
4、由dup函数返回的文件描述符与作为参数传递给该函数的文件描述符标识的是同一个 文件表项,而文件读写位置是保存在文件表项而非文件描述符表项中的,因此通过这 些文件描述符中的任何一个,对文件进行读写或随机访问,都会影响通过其它文件描 述符操作的文件读写位置。这与多次通过open函数打开同一个文件不同。
int dup2(int oldfd, int newfd);
功能:复制文件描述符表的特定条目到指定项:
参数:oldfd:源文件描述符 newfd:目标文件描述符
返回值:成功返回目标文件描述符(newfd),失败返回-1。
dup2函数在复制由oldfd参数所标识的源文件描述符表项时,会先检查由newfd参数所标 识的目标文件描述符表项是否空闲,若空闲则直接将前者复制给后者,否则会先将目标文 件描述符newfd关闭,使之成为空闲项,再行复制。
int access(char const* pathname, int mode);
功能:判断当前进程是否可以对某个给定的文件执行某种访问。
参数:pathname 文件路径 mode 被测试权限,可以以下取值
R_OK - 可读否
W_OK - 可写否
X_OK - 可执行否
F_OK - 存在否
返回值:成功返回0,失败返回-1。
int truncate(char const* path, off_t length);
功能:修改指定文件的大小
参数:path 文件路径
length 文件大小
返回值:成功返回0,失败返回-1。
该函数既可以把文件截短,也可以把文件加长,所有的改变均发生在文件的 尾部,新增加的部分用数字0填充。
int ftruncate(int fd, off_t length);
功能:修改指定文件的大小
参数:fd 文件描述符
length 文件大小
返回值:成功返回0,失败返回-1。
该函数既可以把文件截短,也可以把文件加长,所有的改变均发生在文件的 尾部,新增加的部分用数字0填充。
pid_t getpid(void);
功能:返回调用进程的PID
pid_t getppid(void);
功能:返回调用进程的父进程的PID
uid_t getuid(void);
功能:返回调用进程的实际用户ID
gid_t getgid(void);
功能:返回调用进程的实际组ID
uid_t geteuid(void);
功能:返回调用进程的有效用户ID
gid_t getegid(void);
功能:返回调用进程的有效组ID
pid_t fork(void);
功能:创建调用进程的子进程
返回值:成功分别在父子进程中返回子进程的PID和0,失败返回-1。
注意:该函数调用一次返回两次,在父进程中返回所创建子进程的PID,而在子进 程中返回0,函数的调用者可以根据返回值的不同,分别为父子进程编写不同的处理分支系统中总的线程数达到了上线,或者用户的总进程数达到了上线,fork函数会返回失败。
•线程上线:/proc/sys/kernel/threads-max
•进程上线:ulimit -u
void _exit(int status);
参数:status 进程退出码,相当于main函数的返回值
注意:该函数不返回!
拓展:
_exit在终止调用进程之前也会做几件收尾工作,但与exit函数所做的不同。事实上,exit 函数在做完它那三件收尾工作之后紧接着就会调用_exit函数
A、关闭所有仍处于打开状态的文件描述符
B、将调用进程的所有子进程托付给init进程收养
C、向调用进程的父进程发送SIGCHLD(17)信号
D、令调用进程终止运行,将status的低八位作为退出码保存在其终止状态中
int execl (const char* path, const char* arg, ...);族6
int execl (const char* path, const char* arg, ...);
int execlp (const char* file, const char* arg, ...);
int execle (const char* path, const char* arg, ...,char* const envp[]);
int execv (const char* path, char* const argv[]);
int execvp (const char* file, char* const argv[]);
int execve (const char* path, char* const argv[],char* const envp[]);
exec函数族一共包括6个函数,它们的函数名都是在exec后面加上一到两个 字符后缀,不同的字符后缀代表不同的含义:
l:即list,新进程的命令行参数以字符指针列表(const char* arg, ...)的形式传入,列表以空指针结束
p:即path,若第一个参数中不包含“/”,则将其视为文件名,并根据PATH环境变量搜索该文件
e:即environment,新进程的环境变量以字符指针数组(char* const envp[])的形式传入, 数组以空指针结束,不指定环境变量则从调用进程复制
v:即vector,新进程的命令行参数以字符指针数组(char* const argv[])的形式传入,数组以空指针结束
拓展:
1、其实6个exec函数中只有execve是真正的系统调用,其它5个函数不过是对execve函数的简单包装
2、调用exec函数不仅改变调用进程的地址空间和进程映像,调用进程的一些属性也发生了变化:
-任何处于阻塞状态的信号都会丢失
-被设置为捕获的信号会还原为默认操作
-有关线程属性的设置会还原为缺省值
-有关进程的统计信息会复位
-与进程内存相关的任何数据都会丢失,包括内存映射文件
-标准库在用户空间维护的一切数据结构(如通过atexit或on_exit函数注册的退出处理函数) 都会丢失
3、但也有些属性会被新进程继承下来,比如PID、PPID、实际用户ID和实际组 ID、优先级,以及文件描述符等
4、注意如果进程创建成功,exec函数是不会返回的,因为成功的exec调用会以 跳转到新进程的入口地址作为结束,而刚刚运行的代码是不会存在于新进程的 地址空间中的。但如果进程创建失败,exec函数会返回-1
5、调用exec函数固然可以创建出新的进程,但是新进程会取代原来的进程。如 果既想创建新的进程,同时又希望原来的进程继续存在,则可以考虑 fork+exec模式,即在fork产生的子进程里调用exec函数,新进程取代了子进 程,但父进程依然存在
int pause(void);
功能:无限睡眠
返回值:成功阻塞,失败返回-1
注意:该函数使调用进(线)程进入无时限的睡眠状态,直到有信号终止了该进程或被其捕获。如 果有信号被调用进程捕获,在信号处理函数返回以后,pause函数才会返回,其返回值-1, 同时置errno为EINTR,表示阻塞的系统调用被信号打断。pause函数要么不返回,要么 返回-1,永远不会返回0。
unsigned int sleep(unsigned int seconds);
功能:有限睡眠 Ø参数:seconds 以秒为单位的睡眠时限
返回值:返回0或剩余秒数。
注意:
1、该函数使调用进程睡眠seconds秒,除非有信号终止了调用进程或被其捕获
2、如果有信号被调用进程捕获,在信号处理函数返回以后,sleep函数才会返回,且返回值为剩余的秒数,否则该函数将返回0,表示睡眠充足
int usleep (useconds_t usec);
功能:更精确的有限睡眠
参数:usec 以微秒(1微秒=10-6秒)为单位的睡眠时限
返回值:成功返回0,失败返回-1
注意:如果有信号被调用进程捕获,在信号处理函数返回以后,usleep函数才会返回,且返回 值为-1,同时置errno为EINTR,表示阻塞的系统调用被信号中断
unsigned int alarm(unsigned int seconds);
功能:设置闹钟
参数:seconds 以秒为单位的闹钟时间。
返回值:返回0或先前所设闹钟的剩余秒数。
注意:
1、alarm函数使系统内核在该函数被调用以后seconds秒的时候,向调用进程发送 SIGALRM(14)信号
2、若在调用该函数前已设过闹钟且尚未到期,则该函数会重设闹钟,并返回先前所设闹钟的 剩余秒数,否则返回0
3、若seconds取0,则表示取消先前设过且尚未到期的闹钟
int pipe(int pipefd[2]);
功能:创建无名管道
参数:pipefd 输出两个文件描述符:
pipefd[0] - 用于从无名管道中读取数据;
pipefd[1] - 用于向无名管道中写入数据。
返回值:成功返回0,失败返回-1
#include<sys/mman.h>
<sys/mman.h> 是一个标准库头文件,不过它所声明的函数大多涉及系统调用。
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
功能:建立虚拟内存到物理内存或磁盘文件的映射:
参数:
start:映射区虚拟内存的起始地址,NULL系统自动选定后返回。
length:映射区字节数,自动按页圆整。
prot:映射区操作权限,可取以下值:
PROT_READ - 映射区可读
PROT_WRITE - 映射区可写
PROT_EXEC - 映射区可执行
PROT_NONE - 映射区不可访问
flags:映射标志,可取以下值:
MAP_ANONYMOUS- 匿名映射,将虚拟内存映射到物理内存而非文件,忽略 fd和offset参数 MAP_PRIVATE - 对映射区的写操作只反映到缓冲区中并不会真正写入文件
MAP_SHARED - 对映射区的写操作直接反映到文件中
MAP_DENYWRITE - 拒绝其它对文件的写操作
MAP_FIXED - 若在start上无法创建映射,则失败(无此标志系统会自动调整)
fd:文件描述符
offset:文件偏移量,自动按页(4K)对齐
返回值:成功返回映射区虚拟内存的起始地址,失败返回MAP_FAILED(-1)。
int munmap(void* start, size_t length);
功能:解除虚拟内存到物理内存或磁盘文件的映射:
参数:start:映射区虚拟内存的起始地址。
length:映射区字节数,自动按页圆整。
返回值:成功返回0,失败返回-1。
注意:munmap允许对映射区的一部分解映射,但必须按页处理
内存映射的建立和解除
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main() {// 打开文件int fd = open("test.txt", O_RDONLY);if (fd == -1) {perror("open");return 1;}// 获取文件大小struct stat sb;if (fstat(fd, &sb) == -1) {perror("fstat");close(fd);return 1;}// 建立内存映射char *addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (addr == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 打印映射区域的内容printf("文件内容:\n%s\n", addr);// 解除内存映射if (munmap(addr, sb.st_size) == -1) {perror("munmap");}// 关闭文件描述符close(fd);return 0;
}
#include<fcntl.h>
int open(char const* pathname, int flags, mode_t mode);
功能:打开已有的文件或创建新文件
参数:pathname 文件路径 flags 状态标志,可以以下取值
O_RDONLY - 只读
O_WRONLY - 只写
O_RDWR - 读写
O_APPEND - 追加
O_CREAT - 不存在即创建,已存在即打开
O_EXCL - 不存在即创建,已存在即报错
O_TRUNC - 不存在即创建,已存在即清空
mode 权限模式 仅在创建新文件时有效,可用形如0XXX的三位八进制数表示,由高位到低位依次 表示拥有者用户、同组用户和其它用户的读、写和执行权限,读权限用4表示,写权限用2表示,执行权限用1表示,最后通过加法将不同的权限组合在一起
返回值:所返回的一定是当前未被使用的,最小文件描述符
注意:调用进程的权限掩码会屏蔽掉创建文件时指定的权限位, 如创建文件时指定权限0666, 进程权限掩码0022,所创建文件的实际权限为:0666&~0022=0644 (r w-r--r--)
int fcntl(int fd, F_SETLK/F_SETLKW,struct flock* lock);
功能:加解锁
参数:
F_SETLK 非阻塞模式加锁,F_SETLKW 阻塞模式加锁
lock 对文件要加的锁
返回值:成功返回0,失败返回-1
struct flock {short l_type; // 锁类型:F_RDLCK/F_WRLCK/F_UNLCKshort l_whence; // 锁区偏移起点:SEEK_SET/SEEK_CUR/SEEK_ENDoff_t l_start; // 锁区偏移字节数off_t l_len; // 锁区字节数pid_t l_pid; // 加锁进程的PID,-1表示自动设置};
通过对该结构体类型变量的赋值,再配合fcntl函数,以完成对文件指定区域的 加解锁操作
几点说明:
1、当通过close函数关闭文件描述符时,调用进程在该文件描述符上所加的一切锁将被自动 解除;
2、当进程终止时,该进程在所有文件描述符上所加的一切锁将被自动解除;
3、文件锁仅在不同进程之间起作用,同一个进程的不同线程不能通过文件锁解决读写冲突问 题;
4、通过fork/vfork函数创建的子进程,不继承父进程所加的任何文件锁;
5、通过exec函数创建的新进程,会继承原进程所加的全部文件锁,除非某文件描述符带有 FD_CLOEXEC标志。
从前述基于锁的操作模型可以看出,锁机制之所以能够避免读写冲突,关键 在于参与读写的多个进程都在按照一套模式——先加锁,再读写,最后解 锁——按部就班地执行。这就形成了一套协议,只要参与者无一例外地遵循 这套协议,读写就是安全的。反之,如果哪个进程不遵守这套协议,完全无视 锁的存在,想读就读,想写就写,即便有锁,对它也起不到任何约束作用。因 此,这样的锁机制被称为劝谏锁或协议锁。
文件锁的内核结构
每次对给定文件的特定区域加锁,都会通过fcntl函数向系统内核传递flock结 构体,该结构体中包含了有关锁的一切细节,诸如锁的类型(读锁/写锁),锁 区的起始位置和大小,甚至加锁进程的PID(填-1由系统自动设置)。
系统内核会收集所有进程对该文件所加的各种锁,并把这些flock结构体中的 信息,以链表的形式组织成一张锁表,而锁表的起始地址就保存在该文件的v 节点中。
任何一个进程通过fcntl函数对该文件加锁,系统内核都要遍历这张锁表,一 旦发现有与欲加之锁构成冲突的锁即阻塞或报错,否则即将欲加之锁插入锁表, 而解锁的过程实际上就是调整或删除锁表中的相应节点。
#include<sys/stat.h>
int stat(char const* path, struct stat* buf);
功能:从i节点中提取文件的元数据,即文件的属性信息
参数:path 文件路径 buf 文件元数据结构
返回值:成功返回0,失败返回-1
文件元数据结构
stat函数族通过stat结构体,向调用者输出文件的元数据:
struct stat {dev_t st_dev; // 设备IDino_t st_ino; // i节点号mode_t st_mode; // 文件的类型和权限nlink_t st_nlink; // 硬链接数uid_t st_uid; // 拥有者用户IDgid_t st_gid; // 拥有者组IDdev_t st_rdev; // 特殊设备IDoff_t st_size; // 总字节数blksize_t st_blksize; // I/O块字节数blkcnt_t st_blocks; // 存储块数time_t st_atime; // 最后访问时间time_t st_mtime; // 最后修改时间time_t st_ctime; // 最后状态改变时间
}
stat结构的st_mode成员表示文件的类型和权限,该成员在stat结构中被声 明为mode_t类型,其原始类型在32位系统中被定义为unsigned int,即32位 无符号整数,但到目前为止,只有其中的低16位有意义
用16位二进制数(B15...B0)表示的文件类型和权限,从高到低可被分为五组
B15 - B12 : 文件类型
B11 - B9 : 设置用户ID,设置组ID,粘滞
B8 - B6 : 拥有者用户的读、写和执行权限
B5 - B3 : 拥有者组的读、写和执行权限
B2 - B0 : 其它用户的读、写和执行权限
文件类型:B15 - B12
设置用户ID、设置组ID和粘滞:B11 - B9
设置用户ID、设置组ID和粘滞:B11 - B9
系统中的每个进程其实都有两个用户ID,一个叫实际用户ID,一个叫有效用户ID
进程的实际用户ID继承自其父进程的实际用户ID。当一个用户通过合法的用户名和口令 登录系统以后,系统就会为他启动一个Shell进程,Shell进程的实际用户ID就是该登录用 户的用户ID。该用户在Shell下启动的任何进程都是Shell进程的子进程,自然也就继承了 Shell进程的实际用户ID
一个进程的用户身份决定了它可以访问哪些资源,比如读、写或者执行某个文件。但真正 被用于权限验证的并不是进程的实际用户ID,而是其有效用户ID。一般情况下,进程的 有效用户ID就取自其实际用户ID,可以认为二者是等价的
但是,如果用于启动该进程的可执行文件带有设置用户ID位,即B11位为1,那么该进程 的有效用户ID就不再取自其实际用户ID,而是取自可执行文件的拥有者用户ID
系统管理员常用这种方法提升普通用户的权限,让他们有能力去完成一些本来只有root用 户才能完成的任务。例如,他可以为某个拥有者用户为root的可执行文件添加设置用户 ID位,这样一来无论运行这个可执行文件的实际用户是谁,启动起来的进程的有效用户 ID都是root,凡是root用户可以访问的资源,该进程都可以访问。当然,具体访问哪些 资源,以何种方式访问,还要由这个可执行文件的代码来决定。作为一个安全的操作系统, 不可能允许一个低权限用户在高权限状态下为所欲为。如通过passwd命令修改口令
带有设置用户ID位的不可执行文件:没有意义。
带有设置用户ID位的目录文件:没有意义。
与设置用户ID位的情况类似,如果一个可执行文件带有设置组ID位,即B10 位为1,那么 运行该可执行文件所得到的进程,它的有效组ID同样不取自其实际组ID,而是取自可执 行文件的拥有者组ID
带有设置组ID位的不可执行文件:某些系统上用这种无意义的组合表示强制锁。
带有设置组ID位的目录文件:在该目录下创建文件或子目录,其拥有者组取自该目录的 拥有者组,而非创建者用户所隶属的组。
带有粘滞位(B9)的可执行文件,在其首次运行并结束后, 其代码区被连续地保存在磁盘交 换区中,而一般磁盘文件的数据块是离散存放的。因此,下次运行该程序可以获得较快的 载入速度
带有粘滞位(B9)的不可执行文件:没有任何意义
带有粘滞位(B9)的目录: 除root以外的任何用户在该目录下,都只能删除或者更名那些 属于自己的文件或子目录,而对于其它用户的文件或子目录,既不能删除也不能改名,如 /tmp目录
拥有者用户的读、写和执行权限:B8 - B6
拥有者组的读、写和执行权限:B5 - B3
其他用户的读、写和执行权限:B2 - B0
辅助分析文件类型的实用宏
S_ISREG() :是否普通文件
S_ISDIR() :是否目录
S_ISSOCK() :是否本地套接字
S_ISCHR() :是否字符设备
S_ISBLK() :是否块设备
S_ISLNK() :是否符号链接
S_ISFIFO() :是否有名管道
int lstat(char const* path, struct stat* buf);
功能:从i节点中提取文件的元数据,即文件的属性信息
参数:path 文件路径 buf 文件元数据结构
返回值:成功返回0,失败返回-1
注意:lstat()函数与另外两个函数的区别在于它不跟踪符号链接。
例:
abc.txt ---> xyz.txt abc.txt文件是xyz.txt文件的符号链接
stat(“abc.txt”, ... ); //得到xyz.txt文件的元数据
lstat(“abc.txt”, ... ); //得到abc.txt文件的元数据
int fstat(int fd, struct stat* buf);
功能:从i节点中提取文件的元数据,即文件的属性信息
参数:fd 文件描述符 buf 文件元数据结构
返回值:成功返回0,失败返回-1
int mkfifo(char const* pathname, mode_t mode);
功能:创建有名管道
参数:pathname:有名管道名,即管道文件的路径。
mode:权限模式。
返回值:成功返回0,失败返回-1
#include<sys/wait.h>
pid_t wait(int* status);
功能:等待并回收任意子进程
参数:status 用于输出子进程的终止状态,可置NULL
返回值:成功返回所回收的子进程的PID ,失败返回-1
拓展:
1、父进程在创建若干子进程以后调用wait函数:
A.若所有子进程都在运行,则阻塞,直到有子进程终止才返回;
B.若有一个子进程已终止,则返回该子进程的PID并通过status参数输出其终止状态;
C.若没有任何可被等待并回收的子进程,则返回-1,置errno为ECHILD。
2、在任何一个子进程终止前,wait函数只能阻塞调用进程,如果有一个子进程在wait函 数被调用之前,已经终止并处于僵尸状态,wait函数会立即返回,并取得该子进程的终 止状态,同时子进程僵尸消失。由此可见wait函数主要完成三个任务
① 阻塞父进程的运行,直到子进程终止再继续,停等同步
②获取子进程的PID和终止状态,令父进程得知谁因何而死
③为子进程收尸,防止大量僵尸进程耗费系统资源
以上三个任务中,即使前两个与具体需求无关,仅仅第三个也足以凸显wait函数的重 要性,尤其是对那些多进程服务器型的应用而言
3、子进程的终止状态通过wait函数的status参数输出给该函数调用者。头文件提供了几个辅助分析进程终止状态的工具宏 :
WIFEXITED(status)
真:正常终止 WEXITSTATUS(status) -> 进程退出码
假:异常终止 WTERMSIG(status) -> 终止进程的信号
WIFSIGNALED(status)
真:异常终止 WTERMSIG(status) -> 终止进程的信号
假:正常终止 WEXITSTATUS(status) -> 进程退出码
pid_t waitpid(pid_t pid, int* status, int options);
功能:等待并回收任意或特定子进程
参数:pid 可以以下取值:
-1 等待并回收任意子进程,相当于wait函数
>0 等待并回收特定子进程
status 用于输出子进程的终止状态,可置NULL
options 可以如下取值:
0 阻塞模式,若所等子进程仍在运行,则阻塞直至其终止。
WNOHANG 非阻塞模式,若所等子进程仍在运行,则返回0.
返回值:成功返回所回收子进程的PID或者0,失败返回-1。
拓展:
1、waitpid(-1,&status,0) 等价于 wait(&status);
2、事实上,无论一个进程是正常终止还是异常终止,都会通过系统内核向其父进程发送SIGCHLD(17)信号。父进程可以忽略该信号,也可以提供一个针对 该信号的信号处理函数,在信号处理函数中以异步的方式回收子进程。这样做不仅流程简单,而且僵尸的存活时间短,回收效率高。
#include<sys/ipc.h>
key_t ftok (const char* pathname, int proj_id);
功能:用于合成一个键
参数:pathname 一个真实存在的路径名
proj_id:项目ID,仅低8位有效,取0到255之间的数
返回值:成功返回可用于创建或获取IPC对象的键,失败返回-1
#include<sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:创建新的或获取已有的共享内存
参数:key:键。
size:字节数,自动按页取整。
shmflg:创建标志,可取以下值:
0 - 获取,不存在即失败。
IPC_CREAT - 创建,不存在即创建,已存在即获取。
IPC_EXCL - 排它,不存在即创建,已存在即失败。
通过位或组合读写权限。
返回值:成功返回共享内存的ID,失败返回-1。
void* shmat(int shmid, void const* shmaddr, int shmflg);
功能:加载共享内存,将物理内存中的共享区域映射到进程用户空间的虚拟内存中。
参数:shmid:共享内存的ID。
shmaddr:映射到共享内存的虚拟内存起始地址,取NULL,由系统自动选择。
shmflg:加载标志,可取以下值:
0 - 以读写方式使用共享。
SHM_RDONLY - 以只读方式使用共享内存。
返回值:成功返回共享内存的起始地址,失败返回-1。
int shmdt(void const* shmaddr);
功能:卸载共享内存
参数: shmaddr:共享内存的起始地址
返回值:成功返回0,失败返回-1。
注意:shmdt函数负责从调用进程的虚拟内存中结束shmaddr所指向的映射区到共享内存的映 射,同时将系统内核中共享内存的加载计数减1。
int shmctl(int shmid, IPC_RMID, NULL);
功能:销毁共享内存
参数: shmid:共享内存对象ID Ø返回值:成功返回0,失败返回-1。
注意:销毁共享内存。其实并非真的销毁,而只是做一个销毁标记,禁止任何进程对该共享内存 形成新的加载,但已有的加载依然保留。只有当其使用者们纷纷卸载,直至其加载计数降 为0时,共享内存才会真的被销毁
#include<sys/msg.h>
int msgget(key_t key, int msgflg);
功能:创建新的或获取已有的消息队列
参数:key:键。
msgflg:创建标志,可取以下值:
0 - 获取,不存在即失败。
IPC_CREAT - 创建,不存在即创建,已存在即获取。
IPC_EXCL - 排它,不存在即创建,已存在即失败。
通过位或组合读写权限。
返回值:成功返回消息队列的ID,失败返回-1。
int msgsnd(int msgid, void const* msgp, size_t msgsz, int msgflg);
功能:发送消息
参数:
msgid:消息队列的ID。
msgp:指向一个包含消息类型和消息数据的内存块。该内存块的前4个字节必须是 一个大于0的整数,代表消息类型,其后紧跟消息数据
msgsz:期望发送消息数据(不含消息类型)的字节数
msgflg:发送标志,一般取0即可
返回值:成功返回0,失败返回-1。
int msgrcv(int msgid, void* msgp, size_t msgsz, long msgtyp, int msgflg);
Ø功能:接收消息
Ø参数:
msgid:消息队列的ID。
msgp:指向一块包含消息类型(4字节)和消息数据的内存
msgsz:期望接收消息数据(不含消息类型)的字节数
msgflg:接收标志,一般取0即可
msgtyp:消息类型,可取以下值
0- 提取消息队列的第一条消息
>0- 若msgflg参数不包含MSG_EXCEPT位,则提取消息队列的第一条类型 为msgtyp的消息;若msgflg参数包含MSG_EXCEPT位,则提取消息队 列的第一条类型不为msgtyp的消息
<0- 提取消息队列中类型小于等于msgtyp的绝对值的消息,类型越小的消 息越被优先提取
返回值:成功返回实际接收到的消息数据字节数,失败返回-1。
注意:
1、msgrcv函数的msgp参数所指向的内存块中包含消息类型,其值由该函 数输出,但该函数的msgsz参数所表示的期望接收字节数以及该函数所返回的 实际接收字节数中都不包含消息类型所占的4个字节
2、若存在与msgtyp参数匹配的消息,但其数据长度大于msgsz参数,且msgflg 参数包含MSG_NOERROR位,则只截取该消息数据的前msgsz字节返回,剩 余部分直接丢弃;但如果msgflg参数不包含MSG_NOERROR位,则不处理该 消息,直接返回-1,并置errno为E2BIG
3、若消息队列中有可接收消息,则msgrcv函数会将消息移出消息队列,并立即 返回所接收到的消息数据的字节数,表示接收成功,否则此函数会阻塞,直到 消息队列中有可接收消息为止。若msgflg参数中包含IPC_NOWAIT位,则 msgrcv函数在消息队列中没有可接收消息的情况下不会阻塞,而是返回-1,同 时置errno为ENOMSG。
int msgctl(int msgid, IPC_RMID, NULL);
功能:销毁消息队列
参数:msgid:消息队列的ID
返回值:成功返回0,失败返回-1
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
功能:创建套接字
参数:domain:通信域,协议族,可取以下值:
PF_LOCAL/PF_UNIX - 本地套接字,进程间通信
PF_INET - 基于IPv4的网络通信
PF_INET6 - 基于IPv6的网络通信
PF_PACKET - 基于底层包的网络通信
type:套接字类型,可取以下值:
SOCK_STREAM - 流式套接字,基于TCP协议
SOCK_DGRAM - 数据报套接字,基于UDP协议
SOCK_RAW - 原始套接字,工作在传输层以下
protocol:特殊协议,对于流式和数据报套接字而言,只能取0
返回值:成功返回表示套接字对象的文件描述符,失败返回-1。
int bind(int sockfd, struct sockaddr const* addr, socklen_t addrlen);
功能:将套接字和本机的地址结构绑定在一起
参数:
sockfd:套接字描述符。
addr:自己的地址结构。
addrlen:地址结构的字节数
返回值:成功返回0,失败返回-1。
套接字接口库通过地址结构定位一个通信主体,可以是一个文件,可以是一 台远程主机,也可以是执行者自己
基本地址结构,本身没有实际意义,仅用于泛型化参数:
struct sockaddr {sa_family_t sa_family; // 地址族char sa_data[14]; // 地址值
};
本地地址结构,用于AF_LOCAL/AF_UNIX域的本地通信:
struct sockaddr_un {sa_family_t sun_family; // 地址族(AF_LOCAL/AF_UNIX)char sun_path[]; // 本地套接字文件的路径
};
网络地址结构,用于AF_INET域的IPv4网络通信:
struct sockaddr_in {sa_family_t sin_family; // 地址族(AF_INET)in_port_t sin_port; // 端口号(0~65535) - unsigned shortstruct in_addr sin_addr; // IP地址 - unsigned int};
struct in_addr {in_addr_t s_addr;};
typedef uint16_t in_port_t; // 无符号16位整数
typedef uint32_t in_addr_t; // 无符号32位整数
int connect(int sockfd, struct sockaddr const* addr, socklen_t addrlen);
功能:将套接字和对方的地址结构连接在一起
参数:
sockfd:套接字描述符。
addr:对方的地址结构。
addrlen:地址结构的字节数
返回值:成功返回0,失败返回-1。
字节序转换函数
uint32_t htonl(uint32_t hostlong); //长整形主机字节序到网络字节序
uint32_t ntohl(uint32_t netllong); //长整形网络字节序到主机字节序
uint16_t htons(uint16_t hostshort);//短整形主机字节序到网络字节序
uint16_t ntohs(uint16_t netshort);//短整形网络字节序到主机字节序
in_addr_t inet_addr(char const* ip); 点分十进制字符串地址 --> 网络字节序形式整数地址
int inet_aton(char const* ip, struct in_addr* nip); 点分十进制字符串地址 --> 网络字节序形式整数地址
char* inet_ntoa(struct in_addr nip); 网络字节序形式整数地址 --> 点分十进制字符串地址
int listen(int sockfd, int backlog)
功能:启动侦听:在指定套接字上启动对连接请求的侦听功能
参数:
sockfd:套接字描述符,在调用此函数之前是一个主动套接字,是不能感知 连接请求的,在调用此函数并成功返回之后,是一个被动套接字, 具有感知连接请求的能力。
backlog:未决连接请求队列的最大长度,一般取不小于1024的值。
返回值:成功返回0,失败返回-1。
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
功能:等待并接受连接请求,在指定套接字上阻塞,直到连接建立完成。
参数:
sockfd:侦听套接字描述符。
addr:输出连接请求发起方的地址信息。
addrlen:输出连接请求发起方的地址信息字节数。
返回值:成功返回可用于后续通信的连接套接字描述符,失败返回-1。
ssize_t recv(int sockfd, void* buf, size_t count, int flags);
功能:接收数据
参数:
sockfd:这是一个整型变量,代表套接字描述符。套接字描述符是通过 socket() 函数创建套接字后返回的值,它标识了要从哪个套接字接收数据。
buf:这是一个指向缓冲区的指针,接收到的数据会被存储到这个缓冲区中。buf 的类型为 void*,意味着它可以指向任意类型的内存区域。
count:这是一个 size_t 类型的变量,表示缓冲区 buf 的最大容量,即最多能接收多少字节的数据。
若flags取0则与read函数完全等价,另外也可取以下值:
MSG_DONTWAIT - 以非阻塞方式接收数据。
MSG_OOB - 接收带外数据。
MSG_WAITALL - 等待所有数据,即不接收到count字节就不返回。
返回值:成功返回实际接收到的字节数,失败返回-1。
ssize_t send(int sockfd, void const* buf, size_t count, int flags);
功能:发送数据
参数:
sockfd:这是一个整数类型的套接字描述符,它代表了要发送数据的套接字。这个套接字通常是通过 socket() 函数创建,并且可能已经使用 connect() (对于 TCP 客户端)或 bind() 和 listen() 以及 accept() (对于 TCP 服务器)等函数进行了相应的配置。
buf:指向要发送数据的缓冲区的指针。这里的 const 表示函数不会修改这个缓冲区里的数据。buf 可以是任何类型的数据,只要将其转换为 void const* 类型即可。
count:要发送的字节数,它指定了从 buf 指向的缓冲区中取出多少字节的数据进行发送。
若flags取0则与write函数完全等价,另外也可取以下值:
MSG_DONTWAIT - 以非阻塞方式接收数据。
MSG_OOB - 接收带外数据。
MSG_DONTROUTE - 不查路由表,直接在本地网络中寻找目的主机
返回值:成功返回实际发送的字节数,失败返回-1。
lssize_t recvfrom(int sockfd, void* buf, size_t count, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
功能:从哪里接收数据
参数:
sockfd:这是一个整型变量,代表套接字描述符。套接字描述符是通过 socket() 函数创建套接字后返回的值,它标识了要从哪个套接字接收数据。
buf:这是一个指向缓冲区的指针,接收到的数据会被存储到这个缓冲区中。buf 的类型为 void*,意味着它可以指向任意类型的内存区域。
count:这是一个 size_t 类型的变量,表示缓冲区 buf 的最大容量,即最多能接收多少字节的数据。
若flags取0则与read函数完全等价,另外也可取以下值:
MSG_DONTWAIT - 以非阻塞方式接收数据。
MSG_OOB - 接收带外数据。
MSG_WAITALL - 等待所有数据,即不接收到count字节就不返回。
src_addr:输出源主机的地址信息
addrlen:输入输出源主机的地址信息的字节数。
返回值:成功返回实际接收的字节数,失败返回-1
ssize_t sendto(int sockfd, void const* buf, size_t count, int flags, struct sockaddr const* dest_addr, socklen_t addrlen);
功能:发送数据到哪里
参数:前四个参数和函数send相同
dest_addr:目的主机的地址信息。
addrlen:目的主机的地址信息的字节数。
返回值:成功返回实际发送的字节数,失败返回-1
#incluce<netdb.h>
struct hostent* gethostbyname(char const* host_name);
功能:通过参数所传的主机域名,获取主机信息
参数:host_name 主机域名
返回值:函数执行成功返回表示主机信息的结构体指针,失败返回NULL
注意:该函数需要再联网情况下使用
struct hostent {char *h_name; //主机官方名 char **h_aliases; // 主机别名表int h_addrtype; //地址类型 int h_length; //地址长度char **h_addr_list; //IP地址表};
#include<pthread.h>
int pthread_create(pthread_t* tid, pthread_attr_t const* attr, void* (*start_routine)(void*), void* arg)
功能:创建新线程
Ø参数:
tid:输出线程ID。pthread_t即unsigned long int
attr:线程属性,NULL表示缺省属性。
start_routine:线程过程函数指针,所指向的函数将在被创建的线程中执行。
arg:传递给线程过程函数的参数。
Ø返回值:成功返回0,失败返回错误码
线程过程函数
void* thread_proc(void* arg) { ... }
定义线程过程函数,该函数会在所创建的线程中被执行,代表了线程的任务。
而main函数其实就是主线程的线程过程函数。
main函数一旦返回,主线程即告结束。主线程一旦结束,进程即告结束。进程一旦结束, 其所有的子线程统统结束
int pthread_join(pthread_t tid, void** retval);
功能:等待子线程终止,即其线程过程函数返回,并与之会合,同时回收该线程的资源
参数:
tid:线程ID。
retval:输出线程过程函数的返回值
返回值:成功返回0,失败返回错误码。
int pthread_detach(pthread_t tid);
功能:使指定的线程进入分离状态
参数:tid 线程的ID
返回值:成功返回0,失败返回错误码。
pthread_t pthread_self(void);
功能:返回调用线程的(POSIX线程库的)TID。
int pthread_equal(pthread_t t1, pthread_t t2);
pthread_t类型在不同系统会被实现为不同的数据类型,甚至可能会使用结 构体。因此判断两个线程ID是否相等或不相等,最好不要使用"=="或"!="运 算符,因为这些关系运算符只能用于C语言内置的简单类型,而对于结构类型 的数据不适用。
功能:若两个参数所表示的TID相等返回非零,否则返回0。
int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t const* attr);
功能:初始化互斥体
参数:mutex:互斥体 attr:互斥体属性
返回值:成功返回0,失败返回错误码。
也可以静态方式初始化互斥锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_destroy(pthread_mutex_t* mutex);
功能:销毁互斥体
参数:mutex:互斥体
返回值:成功返回0,失败返回错误码。
int pthread_mutex_lock (pthread_mutex_t* mutex);
功能:锁定互斥体
参数:mutex 互斥体
成功:返回0,失败返回错误码
int pthread_mutex_unlock (pthread_mutex_t* mutex);
功能:解锁互斥锁
参数:mutex 互斥锁
成功:返回0,失败返回错误码
int pthread_cond_init (pthread_cond_t* cond,const pthread_condattr_t* attr);
功能:初始化条件变量
参数:
cond 条件变量
attr 条件变量属性
返回值:成功返回0,失败返回错误码
也可以静态方式初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_destroy(pthread_cond_t* cond)
功能:销毁条件变量
参数:cond 条件变量
返回值:成功返回0,失败返回错误码
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
功能:睡入条件变量
参数:
cond 条件变量
mutex 互斥锁
返回值:成功返回0,失败返回错误码
拓展:
1、pthread_cond_wait函数会令调用线程进入阻塞状态,直到条件变量cond收到信号为 止,阻塞期间互斥体mutex被解锁
2、条件变量必须与互斥体配合使用,以防止多个线程同时进入条件等待队列时发生竞争
线程在调用pthread_cond_wait函数前必须先通过pthread_mutex_lock函数锁定mutex互斥体
在调用线程进入条件等待队列之前,mutex互斥体一直处于锁定状态,直到调用线程进入条件等待 队列后才被解锁
当调用线程即将从pthread_cond_wait函数返回时,mutex互斥体会被重新锁定,回到调用该函数 之前的状态
int pthread_cond_signal(pthread_cond_t* cond);
功能:唤醒在条件变量中睡眠的一个线程
参数:cond 条件变量
返回值:成功返回0,失败返回错误码
拓展:
一个线程调用pthread_cond_wait函数进入阻塞状态,直到条件变量cond收 到信号为止,阻塞期间互斥锁mutex会被释放。另一个线程通过 pthread_cond_signal函数向条件变量cond发送信号,唤醒在其中睡眠的一 个线程,该线程即从pthread_cond_wait函数中返回,同时重新获得互斥锁 mutex。
#include<sys/syscall.h>
long int syscall(SYS_gettid);
功能:syscall(SYS_gettid)函数返回是一个long int类型整数,是系统内核产生线程唯一标识。一个进程的PID其实就是它的主线程的TID。
返回调用线程的(系统内核的)TID。