Jeff的linux环境编程第三天:文件相关及信号(我的头好大啊!)

文件相关

文件同步:

1、在写入数据时内存与磁盘之间也有一个缓冲区,这种机制降低了磁盘读写次数,提高了读写的效率。
2、但这种机制带来的后果就是磁盘中的数据与实写入的数据不匹配,系统提供了一个函数可以让缓冲区中的数据立即写入到磁盘。

void sync(void);
功能:把缓冲区中的数据同步到磁盘
注意:并不等到数据同步完成后才返回,而是把缓冲区的数据加入到写入队列。

int fsync(int fd);
功能:把指定文件的内容从缓冲区同步到磁盘
注意:会等到完全定稿磁盘才返回

int fdatasync(int fd);
功能:把指定文件的内容从缓冲区同步到磁盘,只同步文件的内容不同步属性。

文件属性:

int stat(const char *path, struct stat *buf);
功能:根据文件的路径获取文件的属性
buf:存储文件属性的结构休指针,是个输出型参数。

int fstat(int fd, struct stat *buf);
功能:根据文件描述符获取文件的属性

int lstat(const char *path, struct stat *buf);
功能:获取软链接文件的文件属性。

struct stat {
dev_t     st_dev;   // 设备ID
ino_t     st_ino;   // i节点号
mode_t    st_mode;  // 文件的类型和权限
nlink_t   st_nlink; // 硬链接数
uid_t     st_uid;   // 用户ID
gid_t     st_gid;   // 组ID
dev_t     st_rdev;  // 特殊设备ID号
off_t     st_size;  // 总字节数
blksize_t st_blksize; // IO块字节数
blkcnt_t  st_blocks;  // 占用512字节块数
time_t    st_atime;   // 最后访问时间
time_t    st_mtime;   // 最后内容修改时间
time_t    st_ctime;   // 最后状态修改时间

st_mode  
    S_ISREG(m)  普通文件
    S_ISDIR(m)  目录文件
    S_ISCHR(m)  字符设备文件
    S_ISBLK(m)  块设备文件
    S_ISFIFO(m) 管道文件
    S_ISLNK(m)  软链接文件
    S_ISSOCK(m) socket文件

S_IFMT     0170000   获取文件类型的掩码
S_IFSOCK   0140000   socket文件
S_IFLNK    0120000   软链接文件
S_IFREG    0100000   普通文件
S_IFBLK    0060000   块设备文件
S_IFDIR    0040000   目录文件
S_IFCHR    0020000   字符设备文件
S_IFIFO    0010000   管道文件
S_ISUID    0004000   设置用户ID
S_ISGID    0002000   设置组ID
S_ISVTX    0001000   sticky bit (see below)
S_IRWXU    00700     用户权限掩码
S_IRUSR    00400     
S_IWUSR    00200     
S_IXUSR    00100     
S_IRWXG    00070     组权限掩码
S_IRGRP    00040     
S_IWGRP    00020     
S_IXGRP    00010     
S_IRWXO    00007     其他用户权限掩码
S_IROTH    00004     
S_IWOTH    00002     
S_IXOTH    00001  

文件的权限:

int access(const char *pathname, int mode);
功能:测试当前用户对文件的权限
pathname:文件的路径
mode:想测试的权限
返回值:存在返回0,不存在返回-1。
    F_OK 文件是否存在
    W_OK 写权限
    R_OK 读权限
    X_OK 执行权限

int chmod(const char *path, mode_t mode);
功能:根据文件的路径修改文件权限
path:文件的路径
mode:由三个8进行组成的权限码 
    0644 普通文件
    0755 可执行文件

int fchmod(int fd, mode_t mode);
功能:根据文件描述符修改文件的权限
fd:文件描述符

mode_t umask(mode_t mask);
功能:设置当前进程的权限屏蔽码
mask:想要设置的权限屏蔽码
返回值:旧的权限屏幕码
注意:权限屏蔽码默认是当前终端的,该函数的设置只对当前进程有效,进行结束后就失效了。

权限屏蔽码:
    如果我们不让新创建的文件具有某些权限,可以设置权限过滤,记录在权限屏蔽码中。
    权限屏蔽码对于chmod命令和函数是无效。

修改文件的大小

int truncate(const char *path, off_t length);
功能:根据文件路径修改文件的大小
length:想要修改的的字节数

int ftruncate(int fd, off_t length);
功能:根据文件描述符修改文件的大小
length:想要修改的的字节数

练习1:实现一个函数,可以删除文件的[n,m)个字节。
int del_file(const char* path ,size_t n,size_t m);

删除和重命名:
int remove(const char *pathname);
功能:标准库中删除文件函数,底层调用的是unlink

int unlink(const char *pathname);
功能:删除硬链接文件

int rename(const char *oldpath, const char *newpath);

链接文件:

int link(const char *oldpath, const char *newpath);
功能:创建硬链接文件

int symlink(const char *oldpath, const char *newpath);
功能:创建软链接文件

ssize_t readlink(const char *path, char *buf, size_t bufsiz);
功能:只读取软链接文件本身,而非链接目标,读取的内容就是链接目录的路径

目录操作:

int mkdir(const char *pathname, mode_t mode);
功能:创建目录
mode:目录的权限,注意必须要有执行权限,否则无法进入

int rmdir(const char *pathname);
功能:删除空目录

int chdir(const char *path);
功能:进入目录,相当于cd命令

char *getcwd(char *buf, size_t size);
功能:获取当前目录,相当于pwd命令

DIR *opendir(const char *name);
功能:打开文件文件,返回一个目录流

struct dirent *readdir(DIR *dirp);
功能:从目录流中读取一条记录
struct dirent {
    ino_t d_ino;    // i节点编号
    off_t d_off;    // 下一个条目的偏移量
    unsigned short d_reclen; // 当前条目的长度
    unsigned char  d_type;   // 文件类型
        DT_BLK      块设备文件
        DT_CHR      字符设备文件
        DT_DIR      目录文件
        DT_FIFO     管道文件
        DT_LNK      软链接文件
        DT_REG      普通文件
        DT_SOCK     socket文件
        DT_UNKNOWN  未知类型
    char           d_name[256];  // 文件名

int closedir(DIR *dirp);
功能:关闭目录流

void seekdir(DIR *dirp, long offset);
功能:设置目录流的位置指针,用于随机读取

void rewinddir(DIR *dirp);
功能:设置目录流的位置指针到开头

long telldir(DIR *dirp);
功能:获取目录流的位置指针

基本概念

1、中断

    当程序接收消息后中止当前正在执行的程序,转而执行其它任务,等其它任务执行完成后再返回,这种执行模式叫中断,分为硬件中断和软件中断。

2、信号

    是一种软件中断,由操作系统发出,程序接收后会执行相应的操作。

3、常见信号

    kill -l 显示所有信号
    SIGINT  Ctrl+c      终止
    SIGQUIT Ctrl+\      终止+core
    SIGFPE  除0         终止+core
    SIGSEGV 非常内存访问 终止+core
    SIGKILL 终止信号     终止

4、不可靠信号和可靠信号

    建立在早期的信号处理机制上(1~31) 是不可靠信号。
    不支持排除,可能会丢失,同一个信号如果连续产生多次,进程可能只接收到一次。
    建立在新信号处理机制上 (34~64) 是可靠信号,支持排除,不会丢失。

5、信号来源

    硬件异常:除0、无效内存访问、未定义指令、总线错误、软件异常。
    软件异常:通过一些命令、函数产生的信号。

6、信号的处理方式

    1、忽略
    2、终止进程
    3、终止进程并产生core文件
    4、捕获并处理(当信号发前,向内核注册一个函数,当信号发生时系统自动执行该函数)。

信号捕获:
typedef void (*sighandler_t)(int);
功能:信号处理函数的格式

sighandler_t signal(int signum, sighandler_t handler);
功能:向信号注册一个信号处理函数
signum:信号编号
handler:函数指针
    SIG_IGN 忽略
    SIG_DFL 按默认处理
返回值:
    之前的信号处理方式

注意:有些系统通过signal注册的函数只执行一次,如果想持续有效,可以在信号处理函数中再注册一次。

注意:子进程会继承父进程的信号处理方式,但如果是通过exec系列函数创建的子进程,会恢复默认的信号处理式。
注意:信号处理完后会返回到产生信号的代码处理,如果我们捕获并处理段错误或算术异常可能会产生死循环,正确处理段错误和算术异常应该是备份数据并结束进程。

信号的发送:

键盘:
    Ctrl+c
    Ctrl+\
    Ctrl+z
错误:
    除0
    非法内存访问
    硬件故障 总线错误
命令:
    kill 信号 进程号
    killall 信号 进程名
函数:
    int kill(pid_t pid, int sig);
    功能:向指定的进程发送信号

    int raise(int sig);
    功能:向进程自己发送信号

    void abort(void);
    功能:向进程自己发送SIGABRT信号

    unsigned int alarm(unsigned int seconds);
    功能:让内核在seconds后向进程发关这SIGALRM信号
    返回值:上次alarm设置的剩余时间
    注意:如果再次调用会覆盖之前的设置,而不会产生两次闹钟信号。

进程休眠与信号:

int pause(void);
功能:让调用者进入休眠状态,直接进程遇到信号(捕获处理、进程结束)
返回值:要么一直休眠不返回,要么返回-1。
相当于没有时间限制的sleep

unsigned int sleep(unsigned int seconds);
功能:让调用者进入休眠指定的秒数,当遇到信号时会提前返回。
返回值:剩余的休眠时间

信号集与信号阻塞:

信号集:是一种数据类型,可以存储多个信号。
    sigset_t 128二进制,每一次都代码一个信号。
相关函数:
    int sigemptyset(sigset_t *set);
    功能:清空信号集

    int sigfillset(sigset_t *set);
    功能:填满信号集

    int sigaddset(sigset_t *set, int signum);
    功能:向信号集中添加信号

    int sigdelset(sigset_t *set, int signum);
    功能:从信号集中删除信号

    int sigismember(const sigset_t *set, int signum);
    功能:测试信号集中是否有某个信号
    功能:
        0 不存在
        1 存在
        -1 信号非法

信号阻塞:

    当程序在执行一些特殊操作时是不适合处理信号的,此时可以让内核先屏蔽信号,等操作执行完成后再发送信号。
    当信号产生时,内核会在其所维护信号表中为进程设置一个与该信号对应的标记,这个过程叫递送。
    从信号产生到完成递送有个时间间隔,处于这个间隔的信号状态叫未决。
    信号屏蔽就是让信号先处于未决状态,暂停递送,当屏蔽解除时再继续递送。
    每个进程都有一个信号集用于存储要屏蔽的信号。

    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    功能:设置要屏蔽的信号,这些信号存储在信号集里面。
    how:
        SIG_BLOCK 把set中的信号添加到要屏蔽的信号集里。
        SIG_UNBLOCK 从信号集删除set的信号。
        SIG_SETMASK 用set替换之前的信号集。
    set:准备好的信号集
    oldset:获取的信号的集

    int sigpending(sigset_t *set);
    功能:获取未决状态的信号

带附加的信号处理:

int sigaction(int signum, const struct sigaction *act,
                 struct sigaction *oldact);
功能:向内核注册一个信号处理方式
signum:要捕获的信号
act:信号处理函数
oldact:获取旧的信号处理式

struct sigaction {
    void (*sa_handler)(int); // 不带附加数据信号处理函数
    void (*sa_sigaction)(int, siginfo_t *, void *); //带附加数据信号处理函数
    sigset_t   sa_mask; // 信号屏蔽信
        在信号函数函数执行过程中,默认屏蔽当前信号,如果想屏蔽其它信号可以向sa_mask中添加。
    int        sa_flags; // 信号处理标志
        SA_NOCLDSTOP 如果signum是SIGCHLD,则子进程停止时不要向我发送SIGCHLD。
        SA_NOCLDWAIT 如果signum是SIGCHLD,则子进程结束时不要产生僵尸进程。
        SA_NODEFER 在信号处理过程中不要屏蔽当前信号。
        SA_RESETHAND 该信号处理方式执行完成后,还原成默认的处理方式。
        SA_RESTART 系统调用一旦被信号打断,自动重启。
        SA_SIGINFO 使用函数指针2,处理信号
    void     (*sa_restorer)(void); // 保留,NULL
};

siginfo_t {
    int      si_signo;    /* Signal number */
    int      si_errno;    /* An errno value */
    int      si_code;     /* Signal code */
    int      si_trapno;   /* Trap number that caused
                                    hardware-generated signal
                                    (unused on most architectures) */
    pid_t    si_pid;      /* Sending process ID */
    uid_t    si_uid;      /* Real user ID of sending process */
    int      si_status;   /* Exit value or signal */
    clock_t  si_utime;    /* User time consumed */
    clock_t  si_stime;    /* System time consumed */
    sigval_t si_value;    /* Signal value */
    int      si_int;      /* POSIX.1b signal */
    void    *si_ptr;      /* POSIX.1b signal */
    int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
    int      si_timerid;  /* Timer ID; POSIX.1b timers */
    void    *si_addr;     /* Memory location which caused fault */
    long     si_band;     /* Band event (was int in
                                    glibc 2.3.2 and earlier) */
    int      si_fd;       /* File descriptor */
    short    si_addr_lsb; /* Least significant bit of address
                                    (since kernel 2.6.32) */


int sigqueue(pid_t pid, int sig, const union sigval value);
功能:向指定的进程发送信号并附加信号

union sigval {
    int   sival_int; // 整数
    void *sival_ptr; // 指针
};

定时器:

int getitimer(int which, struct itimerval *curr_value);
功能:获取当前的定时方案
which:
    ITIMER_REAL 真实计时器,程序总的运行时间 SIGALRM
    ITIMER_VIRTUAL 虚拟计时器 用户态的运行时间 SIGALRM
    ITIMER_PROF 实际计时器 用户态+内核态的运行时间 SIGPROF
    真实计时器 = 实际计时器 + 休眠时间

int setitimer(int which, const struct itimerval *new_value,
                 struct itimerval *old_value);
功能:设置新的定义方案

struct itimerval {
    struct timeval it_interval; /* next value */
    每次时钟信号产生和间隔时间
    struct timeval it_value;    /* current value */
    第一次时钟信号产生和时间

};

struct timeval {
    long tv_sec;                /* seconds */
    long tv_usec;               /* microseconds */
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值