积累沉淀

待山花烂漫,化茧成蝶

Linux基础

前言:Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。

Linux系统一般有四个主要部分:内核、shell、文件系统、应用程序。前三者一起构成了基本的操作系统,应用程序则是在这个基础上运行的。

Part 1: 标准IO

I/O:input & output,是一切实现的基础

stdio 标准IO  
sysio 系统调用IO(文件IO)

stdio: FILE类型贯穿始终

fopen();
fclose();
fgetc();
fputc();
fgets();
fputs();
fread();    binary read
fwrite();   binary write

printf();
scanf();

fseek();
ftell();
int fseeko(FILE *stream, off_t offset, int whence);  
     node: On  some  architectures,  both off_t and long are 32-bit types, but    
     
     defining _FILE_OFFSET_BITS 64 
     
     with the value 64 (before including any header   files) will turn off_t into a 64-bit type.  

off_t ftello(FILE *stream);

rewind();
fflush();
    1. 缓冲区的作用:大多数情况下是好事,合并系统调用。
    2. 行缓冲:换行时候刷新,满了的时候刷新,强制刷新(标准输出是这样的,因为是终端设备)
    3. 全缓冲:满了的时候刷新,强制刷新(默认是全缓冲,只要不是终端设备)
    4. 无缓冲:如stderr, 需要立即输出的内容
    5. 更改缓冲模式的函数 setvbuf()--- 一般用不上

Part 2: 系统IO/文件IO

fd 是在文件IO中贯穿始终的类型
文件描述符的概念:
文件描述符的概念

1. 实质:整形数---数组的下标,优先使用当前可用范围最小的。
2. 当前数组是在一个进程空间中的,不同进程不会共用。
3. 是进程用来访问操作系统对象的“指针”。

文件IO相关操作:

1. open(const char *pathname, int flags); flags --- 位图
2. flags must be:  O_RDONLY,  O_WRONLY,  or O_RDWR.  
3. or has O_CLOEXEC,  O_CREAT,  O_DIRECTORY,  O_EXCL,  O_NOCTTY,O_NOFOLLOW,  O_TMPFILE,  O_TRUNC... see man 2 open.
4. r ---    O_RDONLY
5. r+ ----  O_RDWR
6. w ----   O_WRONLY|O_CREATE|O_TRUNC
7. w+ ----  O_RDWR|O_TRUNC|O_CREATE
8. read()
9. write()
10. close()
11. lseek

文件IO和标准IO的区别

1. 响应速度 & 吞吐量
2. 如何使一个程序变快?主要考虑上面两个方面进行回答。
3. 标准IO和系统IO 不可混用

IO的效率问题

bufsize 的大小会影响效率,但有一个最佳的bufsize 大小,需要测试。

文件共享

线程共享,在一个进程空间多次打开文件。
进程共享,在两个进程中去打开文件,利用进程间共享。
试题:写一个程序删除一个文件的第10行。

原子操作

1. 不可分割的操作
2. 不可分割的最小单位
3. 解决竞争和冲突
4. 如:tmpnam()

程序中的重定向:dup dup2

dup2(old_fd, new_fd) : 把old_fd 从定向到new_fd,第一,关闭new_fd。 第二,copy old_fd 到new_fd。第三,如果old_fd == new_fd时,什么都不做。

同步:sync fsync, fdatasysnc

1. sync - commit buffer cache to disk,同步内核层面的buf cache
2. 解除设备挂载时用到。 man 2 sync see the details.

fcntl()

1. 文件描述符所变的魔术几乎都来源与该函数。

ioctl()

1. 设备相关的内容

/dev/fd/目录

1. 虚目录

Part 3: File System

文件系统:
一、目录和文件

1. 获取文件属性
    stat():通过文件路径获取属性,面对符号链接文件时获取的是所指向的属性。
    fstat():通过文件描述符获取属性。
    lstat():面对符号链接文件时获取的是符号链接文件的属性。
    文件类型:7种 --- dcb-lsp d:目录文件 c:字符设备文件 b:块设备文件 -:常规文件  
    l:链接文件(符号链接文件)s:网络套接字socket 文件 p:管道文件
2. 文件访问权限
    st_mode 是一个16位的位图,用于表示文件类型,文件访问权限,特殊权限位
3. umask
    作用:防止产生权限过松的文件
4. 文件权限的更改/管理
    chmod();
        chmod a+x big.c --- a+x:所有可读可写可执行 rwxrwxrwx. u+x 代表user rwx.
        g+x: group rwx. o+x :other x.
    fchmod();
5. 粘住位
    t 位 /tmp 目录有t位
6. 文件系统:FAT,UFS
    文件或数据的存储和管理
7. 硬链接,符号链接
    硬链接与目录项是同义词,且建立硬链接有限制:不能给目录建立,不能给分区建立。
    符号链接优点:可跨分区,可以给目录建立。
    link() ---> ln src dest/ln -s src dest.
     unlink()
    remove() ---> rm
    rename() ---> mv
8. utime
    change file last access and modification times.
9. 目录的创建和销毁
    mkdir()
    rmdir()
10. 更改当前工作路径
    chdir(); ---> cd: change working directory.
    fchdir();
    getcwd();---> pwd: get current working directory.
11. 分析目录/读取目录内容
    glob():解析模式/ 统配符 可以实现以下方法的集合。

    opendir();
    closedir();
    readdir();
    rewinddir();
    fseekdir();
    seekdir();
    telldir();

二、系统数据文件和信息

1. /etc/passed
    getpwuid();
    getpwnam();

2. /etc/group
    getgrgid();
    getgrgnam();
3. /etc/shadow
    getspnam();
    crypt();
    getpass();

4. 时间戳: time_t   char *   struct tm
    time();
    gmtime();
    localtime();
    mktime();
    strftime(); 

三、进程环境

1. main() 函数
    int main(int argc, char **argv);
2. 进程的终止
    正常终止:
        1)从main 函数返回
        2)调用exit()
        3) 调用_exit() 或_Exit()
        4) 最后一个线程从其启动例程返回
        5) 最后一个线程调用pthread_exit()
    异常终止:
        1)调用abort()
        2) 接到一个信号并终止
        3) 最后一个线程对其取消请求作出响应 
    atexit();
        在进程正常结束时钩子函数逆序被调用,但是进程如果是调用_exit()或_Exit()不会执行钩子函数
3. 命令行参数的分析
     getopt()
     getopt_long()
4. 环境变量
    key=value
    getenv();
    setenv();
    putenv();
5. c程序的存储空间布局 (pmap p_id)

c程序的存储空间布局

6. 库  
    动态库  
    静态库  
    手工装载库  
        dlopen();  
        dlerror();  
        dlsym();  
        dlclose();  
7. 函数跳转
    setjmp();
        设置跳转点
    longjmp();
        安全跨函数的跳转
8. 资源的获取及控制
    getrlimit();
    setrlimit();

Part 4: Process

进程基本知识, 已经进入多进程。

1. 进程标识符 pid
    1)类型pid_t 有符号16位整数(现在已经扩展根据机器环境有不同的大小)
    2)命令ps (man ps) 例如: ps axf ps axm ps ax -L 
    3)进程号是顺次向下使用
    4)getpid();
    5)getppid(); 
2. 进程的产生
    1)fork();
    2)注意理解关键字:duplicating,意味着拷贝,克隆,一模一样等含义,代码从fork()的位置开始一式两份。  
    3)fork后父子进程的区别:fork的返回值不一样,pid不同,ppid也不同,未决信号和文件锁不继承,资源利用量清零。
    4)init进程:是所有进程的祖先进程 进程号是1号
    5)调度器的调度策略决定了哪个进程先运行,不可假设。
    6)fork() 之前fflush() 的重要性。
    7)子进程exit() 的重要性。
    8)vfork()

3. 进程的消亡及释放资源
    wait();
    waitpid()
    wait3();
    wait4();
4. exec函数族
    execl();
    execlp();
    execle();
    execv();
    execvp();
    注意:exec组函数使用注意fflush 的使用。
5. 用户权限及组权限
    u + s
    g + s
    getuid();
    geteuid();
    getgid();
    getegid();
    setuid();// 常用 例子:mysu.c
    setgid();
    setreuid();
    setregid();
    seteuid();
    setguid();
    chown root ./mysu
    chmod u+s ./mysu

6. 解释器文件
    #!  /bin/bash

7. system();
    理解:fork + exec + wait 封装
    例子: 
    fork() + exec("/bin/sh", "sh", "date + %s < /dev/null", NULL) + wait()的一个简单封装
8. 进程会计
    acct();

9. 进程时间
    进程时间
    times() ---> time ./myexec 

10. 守护进程
    会话 session
        是一个容器,承载进程组。
        标识sid
        setsid() 
            creates a new session if the calling process is not a process   
            group leader.The calling process is the leader of the new session,
            the process group leader of the new process group,
            and has no controlling tty.
    终端
        输入和输出
    setpgid();
    getpgid();
    getpgrp();
    单实例的守护进程:用的是锁文件 /var/run/xxx.pid
    启动脚本文件:/etc/rc1./xx

11. 系统日志
    存放的位置: /var/log
    rsyslogd 服务
    openlog();
    syslog();
    closelog();

Part 5: Concurrency

同步
异步
异步事件的处理:查询法,通知法。
异步事件发生的很稀疏通知法是合适的,发生很频繁用查询法。

一、信号

1. 信号的概念
    信号是软件层面的中断。
    信号的响应依赖于中断。

2. signal();
    kill -l 显示信号
    SIGINT ---> ctrl + c
    信号会打断阻塞的系统调用。

3. 信号的不可靠
    指信号行为的不可靠

4. 可重入函数
    所有的系统调用都是可重入的,一部分库函数也是可重入的。memcpy()可重入,rand()不可重入,
    rand_r() 可重入。

5. 信号的响应过程
    信号从受到到响应有一个不可避免的延迟  
    思考:信号如何忽略掉一个信号的?  
    标准信号为什么要丢失?
    标准信号的响应没有严格的顺序。  
    不能从信号处理函数中随意的往外跳

信号的响应过程

6. 常用函数
    kill(); -- send signal to a process
    raise();-- send a signal to the caller

    alarm();
    setitimer();
    例:使用单一计时器,setitimer()或alarm()构造一组函数,实现任意数量的计时器。

    pause();-- wait a signal
    abort();-- create a core dump file
    system();
        During execution of the command, SIGCHLD will  
        be blocked and SIGINT and SIGQUIT will be  ignored,  
        in  the  process  that  calls  system().
    sleep();
    usleep();
    nanosleep();
    select();
    
7. 信号集
    类型:sigset_t
    sigemptyset();
    sigfillset();
    sigaddset();
    sigismember();

8. 信号屏蔽子/pending 集的处理
    sigprocmask(); 例子:block.c
    sigpending(); --- 不常用


9. 扩展集
    sigsuspend(); -- wait for a signal
        解除信号集马上进入等待一个信号
    sigaction(); -- signal()

10. 实时信号
    范围: [SIGRTMIN, SIGRTMAX]
    不丢失排队,排队的多少查看ulimit -a

二、线程

1. 线程的概念
    一个正在运行的函数  
    posix 线程是一套标准,而不是实现  
    openmp线程  
    线程标识:pthread_t
    pthread_equal();
    pthread_self(); -- obtain ID of the calling thread.

2. 线程的创建
    pthread_create();
    线程的调度取决于调度器策略

    线程的终止
        3种方式:
            1)线程从启动例程返回,返回值就是线程的退出码
            2)线程可以被同一进程中的其他线程取消
            3)线程调用pthread_exit()函数
        pthread_join() -- join with a terminated thread

    栈的清理
        pthread_cleanup_push();
        pthread_cleanup_pop();

    线程的取消选项
        线程取消: pthread_cancel();
        取消有2种状态: 允许和不允许
        允许取消又分为:异步cancel,推迟cancel(默认),推迟至cancel点在响应。
        cancel点:posix定义的cancel点,都是可能引发阻塞的系统调用。
        pthread_setcancelstate(): 设置是否允许取消
        pthread_setcanceltype(): 设置取消方式
        pthread_testcancel(): 本函数什么都不做,就是一个取消点。

    线程分离:
        pthread_detach();

3. 线程的同步
    互斥量: 
        pthread_mutex_t
        pthread_mutex_init();
        pthread_mutex_destroy();
        pthread_mutex_lock();
        pthread_mutex_trylock();
        pthread_mutex_unlock();
        pthread_once(); // 只执行一次

    条件变量:
        pthread_cond_t
        pthread_cond_init();
        pthread_cond_destroy();
        pthread_cond_broadcast();
        pthread_cond_signal();
        pthread_cond_wait(); -- 解锁等待 被通知后抢锁
        pthread_cond_timedwait();

    信号量:
    多写锁:读锁 ---> 共享锁    写锁 ---> 互斥锁

4. 线程属性
    pthread_attr_t 
    pthread_attr_init();
    pthread_attr_destroy();
    pthread_attr_setstacksize();
    见 man pthread_attr_init 的see also

    线程同步的属性
        互斥量属性:
            pthread_mutexattr_init();
            pthread_mutexattr_destroy();
            pthread_mutexattr_setpshared();
            pthread_mutexattr_getpshared();
            clone();
            pthread_mutexattr_gettype();
            pthread_mutexattr_settype();
        
        条件变量:
            pthread_condattr_init();
            pthread_condattr_destroy();

        读写锁属性:

5. 重入
    多线程中的IO
    线程与信号
        pthread_sigmask();
        sigwait();
        pthread_kill();

    线程与fork

Part 6: Advanced IO

非阻塞IO – 阻塞IO
补充:有限状态机编程

1. 非阻塞IO
    简单流程:自然流程是结构化的
    复杂流程:自然流程不是结构化的

2. IO 多路转接
    select(); --- 古老
        以事件(读,写,异常)为单位,来组织文件描述符
        缺陷:监视现场和监视结果是放在同一空间,只要select 有返回,除了你感兴趣的事件,  
        其他的集合都清空,需要重新布置监视现场。监视的事件太单一。

        void FD_CLR(int fd, fd_set *set); ---> 删除
        int  FD_ISSET(int fd, fd_set *set); ---> 测试
        void FD_SET(int fd, fd_set *set); ---> 添加
        void FD_ZERO(fd_set *set); ---> 清空

    poll(); --- 可移植,wait for some events on a fd.
        以文件描述符为单位,来组织事件

    epoll(); --- linux 方言
        epoll_create();
        epoll_ctl();
        epoll_wait();

3. 其他读写函数
    readv();
    writev();

4. 存储映射IO
    mmap(); ---> 映射
    munmap(); ---> 解除映射

5. 文件锁
    fcntl()
    lockf()
    flock()

Part 7: IPC

1.管道
    内核提供,单工(一端为读,一端为写),自同步机制
    匿名管道
        pipe()
    命名管道
        mkfifo()


2. XSI -> SysV
    IPC -> Inter-Process Communication
    主动端:先发包的一方
    被动端:先发包的一方(先运行)

    key:ftok 

    Message Queues

    Shared Memory Segments

    Semaphore Arrays

    以上创建方法都是:xxxget xxxop xxxctl for exmaple:man msgget msgop msgctl semget 
    semop semctl man shemget ...


3. 网络套接字socket
    讨论:跨主机的传输要注意的问题
        1 字节序问题:
            大端模式:就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
            小端模式:就是低字节排放在内存的低地址端,高位字节排放在内存的高地址端。
            主机字节序:host
            网络字节序:network
            解决:_to__: htons, htols, ntohs, ntohs

大端存储
小端存储

        2 对齐:
            
1
2
3
4
5
6
struct 
{
int i;
float f;
char ch;
}
解决:不对齐(让编译器不对齐) 3 类型长度问题: int char 解决:int32_t, uint32_t, int64_t int8_t uint8_t Socket 是什么? 报式套接字: 被动端:(先运行) 1 取得socket 2 给socket 绑定地址(本地地址、端口) 3 收/发 消息 4 关闭socket 主动端: 1 取得socket 2 给socket 绑定地址(可省略,系统会自动分配一个端口) 3 发/收 消息 4 关闭socket UDP 包的推荐长度是512byte, 报头长度为8byte. socket() bind() sendto() recvfrom() inet_pton() inet_ntop() setsockopt() getsockopt() 多点通讯:广播(全网广播,子网广播), 多播/组播 流式套接子: C 端(主动端) 1 获得socket 2 给socket 绑定地址(可省略) 3 发送连接 4 收/发消息 5 关闭 S 端(被动端) 1 获得socket 2 给socket 绑定地址 3 将socket 置为监听模式 4 接受链接 5 收/发消息 6 关闭
Buy me a coffee please.