uc系统中常用命令、标准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
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。
相关文章:
uc系统中常用命令、标准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 硬链接&…...
OpenHarmony - 驱动使用指南,HDF驱动开发流程
OpenHarmony - HDF驱动开发流程 概述 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发…...
C++负载均衡远程调用学习之UDP SERVER功能
目录 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现...
word交叉引用图片、表格——只引用编号的处理方法
交叉引用图片/表格 在“引用”选项卡上的“题注”组中,单击“插入题注”。勾选【从题注中排除标签】。在文中插入题注。 【注 意】 这时候插入的题注只有编号项了。然后手动打上标签【TABLE】,并在标签和编号项之间加上【样式分隔符,AltCt…...
平台介绍-开放API接口-鉴权
平台的理念是一个组织内部只建一套系统。但是现实情况是,组织内部已经建立了很多系统,是不能一次性替代的,只能先搭起平台,然后逐步开始替换。这样就不可避免的存在其他系统和平台进行交互的问题。 平台为此设计了开放API接口。其…...
【Bootstrap V4系列】 学习入门教程之 组件-警告框(Alert)
Bootstrap V4 学习入门教程之 组件-警告框(Alert) 警告框(Alert)一、示例二、链接的颜色三、添加其它内容四、关闭警告框 通过 JavaScript 触发行为触发器本组件所暴露的事件 警告框(Alert) 通过精炼且灵活…...
【服务器通信-socket】——int socket(int domain, int type, int protocol);
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址 AF_INET6 与上面类似,不过是来用IPv6的地…...
洛谷P1014(Cantor 表[NOIP 1999 普及组])题解
题目大意:求Cantor表(按照Z字形排列(如第一项是1/1,然后是1/2,2/1,3/1,2/2))的第N项。 那么,我们需要找出Cantor表的排列规律。根据题目中的Z字形描述&#x…...
【愚公系列】《Manus极简入门》012-自我认知顾问:“内在探索向导”
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! …...
密码学_加密
目录 密码学 01 密码基础进制与计量 02 加解密基操 替换 移位 编码 编码 置换 移位 加解密强度 03 对称加密算法(私钥) 工作过程 缺陷 对称加密算法列举? DES DES算法架构 DES分组加密公式 DES中ECB-CBC两种加密方式 3DES 由于DES密钥太短…...
w317汽车维修预约服务系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
云盘系统设计
需求背景 网盘面向大量C端用户 1000w用户 DAU 20% 每天10次 QPS: 1000w * 0.2 * 10 / 100k 500 峰值估计:500 * 5 2500 功能需求 支持上传,下载,多端共同在线编辑,数据冲突处理 非功能需求 1.latency 20s左右 2.可用性与…...
西电雨课堂《知识产权法》课后作业答案
目录 第 1 章 1.1 课后作业 1.2 课后作业 第 2 章 2.1 课后作业 2.2 课后作业 2.3 课后作业 2.4 课后作业 2.5 课后作业 2.6 课后作业 2.7 课后作业 2.8 课后作业 2.9 课后作业 2.10 课后作业 第 3 章 3.1 课后作业 3.2 课后作业 3.3 课后作业 3…...
通信协议记录仪-产品规格书
以下是为 通信协议记录仪(ProtoLogger Pro) 的详细产品规格书,覆盖 技术细节、场景需求、竞品差异化,确保可作为产品开发、市场营销及竞品分析的核心依据。 通信协议记录仪产品规格书 产品名称:ProtoLogger Pro(中文名称:蹲守…...
订单系统冷热分离方案:优化性能与降低存储成本
随着时间推移,订单数据不断积累。在电商平台或者服务型应用中,订单数据是核心数据之一。然而,随着数据量的增长,如何高效存储、管理和查询这些数据成为了系统架构设计的重要问题。在大多数情况下,订单数据的处理不仅涉…...
数据结构学习笔记
第 1 章 绪论 【考纲内容】 (一)数据结构的基本概念 (二)算法的基本概念 算法的时间复杂度和空间复杂度 【知识框架】 【复习提示】 本章内容是数据结构概述,并不在考研大纲中。读者可通过对本章的学习,初步…...
读懂 Vue3 路由:从入门到实战
在构建现代化单页应用(SPA)时,Vue3 凭借其简洁高效的特性成为众多开发者的首选。 而 Vue3 路由(Vue Router)则是 Vue3 生态中不可或缺的一部分,它就像是单页应用的 “导航地图”,帮助用户在不同…...
Aws S3上传优化
上传大约 3.4GB 的 JSON 文件,zip算法压缩后约为 395MB,上传至 S3 效率优化,有一些优化方案可以提高上传速率。下面是几种可能的优化方式,包括选择压缩算法、调整上传方式、以及其他可能的方案。 方案 1. 选择更好的压缩算法 压…...
Python 数据智能实战 (8):基于LLM的个性化营销文案
写在前面 —— 告别群发轰炸,拥抱精准沟通:用 LLM 为你的用户量身定制营销信息 在前面的篇章中,我们学习了如何利用 LLM 增强用户理解(智能分群)、挖掘商品关联(语义购物篮)、提升预测精度(融合文本特征的流失预警)。我们不断地从数据中提取更深层次的洞察。 然而,…...
html:table表格
表格代码示例: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!-- 标准表格。 --><table border"5"cellspacing&qu…...
2.maven 手动安装 jar包
1.背景 有的时候,maven仓库无法下载,可以手动安装。本文以pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar为例。 2.预先准备 下载文件到本地指定位置。 2.1.安装pom mvn install:install-file \-Dfile/home/wind/tmp/pentaho-aggdesigner-5.1.5-jh…...
C++ unordered_set unordered_map
上篇文章我们讲解了哈希表的实现,这节尝试使用哈希表来封装unordered_set/map 1. unordered_set/map的框架 封装的过程实际上与set/map类似,在unordered_set/map层传递一个仿函数,用于取出key值 由于我们平常使用的都是unordered_set/map&…...
第37课 绘制原理图——放置离页连接符
什么是离页连接符? 前边我们介绍了网络标签(Net Lable),可以让两根导线“隔空相连”,使原理图更加清爽简洁。 但是网络标签的使用也具有一定的局限性,对于两张不同Sheet上的导线,网络标签就不…...
< 自用文 Texas style Smoker > 美式德克萨斯烟熏炉 从设计到实现 (第一部分:烹饪室与燃烧室)
原因: 没钱还馋! 但有手艺。 预计目标: 常见的两种偏置式烟熏炉(Offset Smoker) 左边边是标准偏置式(Standard Offset),右边是反向流动式(Reverse Flow Offset&#x…...
【现代深度学习技术】现代循环神经网络03:深度循环神经网络
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
AimRT从入门到精通 - 03Channel发布者和订阅者
刚接触AimRT的小伙伴可能会疑惑,这个Channel和RPC(后面讲的)到底是什么呢? 但是当我们接触了之后,就会发现,其本质类似ROS的Topic通信!(其本质基于发布订阅模型) 接下来…...
MySQL初阶:数据库基础,数据库和表操作,数据库中的数据类型
1.数据库基础 数据库是一个客户端——服务器结构的程序。 服务器是真正的主体,负责保存和管理数据,数据都存储在硬盘上 数据库处理的主要内容是数据的存储,查找,修改,排序,统计等。 关系型数据库&#…...
AI 驱动的智能交通系统:从拥堵到流畅的未来出行
最近研学过程中发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…...
Python清空Word段落样式的方法
在 Python 中,你可以使用 python-docx 库来操作 Word 文档,包括清空段落样式。以下是几种清空段落样式的方法: 方法一:直接设置段落样式为"Normal" from docx import Documentdoc Document(your_document.docx) # 打…...
[javaEE]网络编程
目录 socket对tcp ServerSocket ServerSocket 构造方法: ServerSocket 方法: socket 实现回显服务器和客户端 由于我们之前已经写多了socket对udq的实现,所以我们这节,主要将重心放在Tcp之上 socket对tcp ServerS…...
组件通信-mitt
mitt:与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信。 第一步:安装mitt npm i mitt 第二步:新建文件:src\utils\emitter.ts // 引入mitt import mitt from "mitt"; //调…...
微软发布了最新的开源推理模型套件“Phi-4-Reasoning
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
Socat 用法详解:网络安全中的瑞士军刀
Socat 用法详解:网络安全中的强大工具 引言 socat(SOcket CAT)是一款功能强大的命令行工具,被誉为“网络瑞士军刀”,广泛应用于数据传输、端口转发和网络调试等场景。它支持多种协议和数据通道(如文件、管…...
精益数据分析(36/126):SaaS商业模式的指标动态与实践案例
精益数据分析(36/126):SaaS商业模式的指标动态与实践案例 在创业与数据分析的学习道路上,我们不断探索各种商业模式的核心要点。今天,依旧怀揣着和大家共同进步的想法,深入研读《精益数据分析》中SaaS商业…...
2.LED灯的控制和按键检测
目录 STM32F103的GPIO口 GPIO口的作用 GPIO口的工作模式 input输入检测 -- 向内检测 output控制输出 -- 向外输出 寄存器 寄存器地址的确定 配置GPIO口的工作模式 时钟的开启和关闭 软件编程驱动 LED 灯 硬件 软件 软件编程驱动 KEY 按键 硬件 软件 按键消抖 代码 STM32F…...
架构师面试(三十八):注册中心架构模式
题目 在微服务系统中,当服务达到一定数量时,通常需要引入【注册中心】组件,以方便服务发现。 大家有没有思考过,注册中心存在的最根本的原因是什么呢?注册中心在企业中的最佳实践是怎样的?注册中心的服务…...
Go-web开发之帖子功能
帖子功能 route.go r.Use(middleware.JWTAuthMiddleware()){r.POST("/post", controller.CreatePostHandler)r.GET("/post/:id", controller.GetPostDetailHandler)}post.go 定义帖子结构 type Post struct {Id int64 json:"id" …...
MYSQL-设计表
一.范式 数据库的范式是⼀组规则。在设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数 据库,这些不同的规范要求被称为不同的范式。 关系数据库有六种范式:第⼀范式(1NF)、第⼆范式(…...
动态思维——AI与思维模型【91】
一、定义 动态思维思维模型是一种强调在思考问题和分析情况时,充分考虑到事物的变化性、发展性和相互关联性,不局限于静态的、孤立的视角,而是以发展变化的眼光看待事物,能够根据不同时间、环境和条件的变化,灵活调整…...
文献阅读篇#7:5月一区好文阅读,BFA-YOLO,用于建筑信息建模!(下)
期刊简介:《Advanced Engineering Informatics》创刊于2002年,由Elsevier Ltd出版商出版,出版周期Quarterly。该刊已被SCIE数据库收录,在中科院最新升级版分区表中,该刊分区信息为大类学科工程技术1区,2023…...
【Linux网络编程】http协议的状态码,常见请求方法以及cookie-session
本文专栏:Linux网络编程 目录 一,状态码 重定向状态码 1,永久重定向(301 Moved Permanently) 2,临时重定向(302 Found) 二,常见请求方法 1,HTTP常见Hea…...
ARM 指令集(ubuntu环境学习)第六章:ARM 编程技巧与优化策略
在本章中,我们将介绍一些在 ARM 架构上编写高效代码的技巧和常见优化策略,帮助您在嵌入式系统中获得更低延迟、更高吞吐和更低功耗。 6.1 寄存器利用与最小化内存访问 多用寄存器 ARM 通用寄存器(r0–r12)数量充足,尽量将临时变量保留在寄存器中,减少对内存的读写。 避免…...
柔性超声耦合剂的选择与设计-可穿戴式柔性超声耦合剂面临的难题
柔性PZT压电薄膜:破解可穿戴式超声耦合剂难题的关键材料! 随着可穿戴技术的快速发展,超声设备正朝着轻量化、柔性化和高集成度方向演进。在医学诊断、健康监测和智能穿戴领域,可穿戴式超声设备因其无创、实时、动态成像等优势受到…...
XCTF-pwn(二)
guess_num 看一下文件信息 利用gets函数将seed[0]给覆盖掉 距离0x20 我们需要输入十次随机数产生的值 写一个c程序先预判当seed是a的时候产生的随机数分别是多少 payload from pwn import* from ctypes import* context.log_leveldebugrremote("61.147.171.105", 6…...
AI外挂RAG:大模型时代的检索增强生成技术
目录 引言 一、RAG是什么? 二、RAG为什么会出现? 三、RAG的工作原理 四、RAG的技术优势 五、RAG的应用场景 六、RAG对AI行业的影响 七、RAG面临的挑战 引言 在人工智能领域,大型语言模型(LLM)如ChatGPT、DeepSe…...
SpringTask
Spring Task是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑 应用场景:信用卡每月还款提醒、火车票售票系统处理未支付订单 fixedDelay:上一次任务执行完成后多长时间(ms)执行下一次任务 fixe…...
Sphinx 文档图片点击放大
文章目录 问题描述解决方案步骤 1:创建 JavaScript 文件步骤 2:编写 JavaScript 代码步骤 3:更新 Sphinx 配置 高级定制为所有图片添加点击功能添加缩放控制 总结 在使用 Sphinx 生成技术文档时,我们经常需要在文档中嵌入截图和示…...
菜鸟之路Day29一一MySQL之DDL
菜鸟之路Day29一一MySQL之DDL 作者:blue 时间:2025.5.2 文章目录 菜鸟之路Day29一一MySQL之DDL0.概述1.DDL之数据库操作1.1查询1.2创建1.3使用1.4删除 2.DDL之表操作2.1创建表2.2数据类型2.3查询表2.4修改表结构2.5删除表 0.概述 文章内容学习自黑马程…...
架构师面试(三十七):监控系统架构模式
题目 监控是在产品生命周期的运维环节,能对产品的关键指标数据进行【实时跟踪】并对异常数据进行【实时报警】。 一句话描述,监控系统可以帮我们【主动预防和发现】业务系统中的问题。 我们常说,监控系统是 “粮草”,业务系统是…...
【Redis】Hash哈希
文章目录 注意个问题hset命令(核心)hget命令(核心)hexists命令hdel命令hkeys和hvals命令hgetall和hmget命令hlen命令hsetnx命令hincrby命令哈希命令小结哈希编码方式使用场景1.关系型数据表保存用户的信息Redis三种缓存方式对比1.…...