第1章——《Unix基础知识》

实验环境介绍

  • gcc:4.8.5

  • glibc:glibc-2.17-222.el7.x86_64

  • os:Centos7.4

  • kernel:3.10.0-693.21.1.el7.x86_64

引言

  • 参考《Unix环境高级编程》写的笔记,算是个人对Unix/Linux类环境上编程接口的一个总结,入门级的小节会直接略过~~~嘿嘿

以下会以知识点 + 代码实验的方式来进行讲解、总结

Unix体系结构

  • 如图所示(自己理解一下):


    Unix体系结构

登录

  • 登录名:略过
  • shell:shell是一个命令行解释器,读取用户的输入,然后执行命令。
    • 我的实验环境使用的是bash,如下图:


      获取shell类型
    • 常见的各系统使用的shell类型如下图:


      常见的各系统使用的shell类型

注意:虽然《Unix环境高级编程》中使用了多种shell来做实验,但是我的笔记、实验中统一在bash环境下进行

文件和目录

  • 省略

输入和输出

  • 文件描述符:一个非负整数,内核用来表示某个进程正在访问的文件。当内核打开(创建)一个文件时,都会返回一个文件描述符。通过这个文件描述符进行文件的读写
  • 标准输入、标准输出和标准错误:每当运行一个程序(进程)时候,所有的shell都为其打开3个描述符,即标准输入、标准输出、标准错误。(至于标准输出、标准输入、标准错误具体指哪个文件,我们今后讨论),下面的例子就是两个进程分别把数据写到标准输出(当前shell,因为unix的设计就是一切皆文件)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFFSIZE(buf) (strlen(buf) + 1)

int
main(int argc, char *argv[])
{
    int n;
    char buf[] = "parent write to stdout\n";
    char buf2[] = "child write to stdout\n";

    pid_t pid = fork();
    if (pid < 0)
        printf("fork error\n");
    else if (pid) {
        /* 父进程 */
        n = write(STDOUT_FILENO, buf, BUFFSIZE(buf));
        printf("parent write %d bytes\n", n);
        if (n < 0)
            printf("parent write error\n");
    } else {
        /* 子进程 */
        n = write(STDOUT_FILENO, buf2, BUFFSIZE(buf2));
        printf("child write %d bytes\n", n);
        if (n < 0)
            printf("child write error\n");
    }
    exit(EXIT_SUCCESS);
}

result:
parent write to stdout
child write to stdout
parent write 24 bytes
child write 23 bytes
  • 不带缓冲的I/O:函数open、read、write、lseek以及close提供不带缓冲的I/O,这些函数都使用文件描述符。

第3章再来详细说明不带缓冲的I/O函数

  • 标准I/O:标准I/O为那些不带缓冲的I/O函数提供了一个带缓冲的接口,这样无需担心如何选取最佳的缓冲区大小。标准I/O函数库提供了使我们能够控制该库所使用的缓冲风格的函数(第五章再来详细讨论缓冲)

程序和进程

  • 程序:程序是一个存储在磁盘上某个目录中的可执行文件。内核使用exec函数(7个exec函数之一),将程序读入内存,并执行。第8章将说明这些exec函数
  • 进程和进程ID:程序执行的实例被称为进程。获取当前程序的进程id,代码如下:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    pid_t pid = getpid();
    printf("current pid is: %d\n", (long)pid);

    exit(EXIT_SUCCESS);
}

result:
current pid is: 33798
  • 进程控制:有3个用于进程控制的主要函数:fork、exec和waitpid(exec函数有7中变体,但是统称为exec函数),在第8章讨论。
  • 线程和线程ID:通常一个进程只有一个控制线程(thread),一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一存储区,所以多线程环境下需要采取同步措施。线程也用ID标识。但是线程ID只在所属的进程内起作用。一个进程中的线程ID在另一个进程中没有意义。在第12章中,在进一步讨论

出错处理

  • 当unix/Linux的系统函数出错时,通常会返回一个负值,然后整型变量errno通常被设置为具有特定信息的值。posix和ISO C将errno定义成一个符号,将它扩展成为一个可修改的整型左值
// 这个是以前的定义
extern int errno;

// Linux支持多线程存取errno的定义
# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable.  */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));

#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#  define errno (*__errno_location ())
#  endif
# endif /* !__ASSEMBLER__ */
  • 使用man 3 errno,查看下实验环境的errnor(部分)说明:
      E2BIG          Argument list too long (POSIX.1)
      EACCES          Permission denied (POSIX.1)
      EADDRINUSE      Address already in use (POSIX.1)
      EADDRNOTAVAIL  Address not available (POSIX.1)
      EAFNOSUPPORT    Address family not supported (POSIX.1)
      EAGAIN          Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1)
      EALREADY        Connection already in progress (POSIX.1)
      EBADE          Invalid exchange
      EBADF          Bad file descriptor (POSIX.1)
      EBADFD          File descriptor in bad state
      EBADMSG        Bad message (POSIX.1)
      EBADR          Invalid request descriptor
      EBADRQC        Invalid request code
      EBADSLT        Invalid slot
      EBUSY          Device or resource busy (POSIX.1)
      ECANCELED      Operation canceled (POSIX.1)
      ECHILD          No child processes (POSIX.1)
      ECHRNG          Channel number out of range
      ECOMM          Communication error on send
      ECONNABORTED    Connection aborted (POSIX.1)
      ECONNREFUSED    Connection refused (POSIX.1)
      ECONNRESET      Connection reset (POSIX.1)
      EDEADLK        Resource deadlock avoided (POSIX.1)
      EDEADLOCK      Synonym for EDEADLK
      EDESTADDRREQ    Destination address required (POSIX.1)
  • errno的规则注意:

    • 如果没有出错,errno的值是不会被例程清楚的。因此只有当函数返回值指明出错的时候,才检查其值。
    • 任何函数都不会把errno的值设置为0,而且在<errno.h>中定义的所有常量都不为0
  • 如何规范检查errno

// 错误的示范
if (somecall() == -1) {
  printf("somecall() failed\n");
  if (errno == ...) { ... }
}

// 规范的使用,因为errno可能会被printf所改变,所以需要在somecall()之后将errno保存下来进行检查
if (somecall() == -1) {
  int errsv = errno;
  printf("somecall() failed\n");
  if (errsv == ...) { ... }
}
  • 打印errno的出错信息
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    // 测试strerror函数
    errno = EACCES;
    fprintf(stderr, "EACCES: %s\n", strerror(errno));

    // 测试perror函数
    errno = ENOENT;
    perror(argv[0]);
    exit(EXIT_SUCCESS);
}

result:
EACCES: Permission denied
./1_8: No such file or directory
  • 出错恢复:errno.h中定义的各种出错分为两类:致命性和非致命性的。
    • 致命性的:无法恢复执行动作。最多能做的是用户屏幕上打印出一条出错消息或者将一条出错消息写入日志文件,然后退出。
    • 非致命性的:可以较妥善地处理,比如资源短缺,当系统活动较少时,这种出错可能不会发生。
    • 与资源相关的非致命性出错包括:EAGAIN、ENFILE、ENOBUFS、ENOLCK、ENOSPC、EWOULDBLOCK
ENOMEM:Not enough space (POSIX.1),有时ENOMEM也是非致命性错误
EBUSY:Device or resource busy (POSIX.1),指明共享资源正在使用
EINTR:中断一个慢速系统调用(可能永远阻塞的系统调用,比如read、recv、select之类的)时,可以将它作为非致命性出错处理

用户标识

  • 用户ID:用户ID为0的用户为root或者超级用户(superuser),其他用户的id也是在创建用户的时候就确定了,不能更改
  • 组ID: 多个用户可能会被分到一个用户组,组ID就是这个组的标识
  • 附属组:一个
  • 使用id命令可以查看当前用户的id、组id、附属组
[root@localhost part_1]# id
uid=0(root) gid=0(root) groups=0(root)
[root@localhost part_1]# 
  • 获取当前进程的id
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    printf("uid = %d, gid = %d\n", getuid(), getgid());
    exit(EXIT_SUCCESS);
}

result:
// 用root用户去运行
uid = 0, gid = 0

// 用一般用户去运行
uid = 1000, gid = 1000

信号

  • 作用:信号用于通知进程发生了某种情况,让进程进行相应的处理
  • 信号的处理方式:
    • 忽略信号
    • 按系统默认方式处理(不同信号的默认处理方式是不同的)
    • 提供一个信号处理函数

这个我们在第10章详细讨论,这个主意的细节比较多

时间值

  • 日历时间:用time_t来保存系统时间戳
  • 进程时间:也称为CPU时间,使用clock_t保存这种时间值。第2章回来讨论如何使用sysconfig得到时钟滴答数
    • 进程时间值:时钟时间(进程运行的时间总量)、用户cpu时间(用户指令所用的时间)、系统cpu时间(内核服务指令使用的时间,如read、write)

    第8章来使用内置函数来获取这三个时间
    * 使用命令来获取某个进程的这3个时间

[root@localhost part_1]# cd /usr/include/
[root@localhost include]# time -p grep _POSIX_SOURCE */*.h > /dev/null 
real 0.02
user 0.00
sys 0.01
[root@localhost include]# 

系统调用和库函数

  • 区别一如图:


    系统调用和库函数
  • 区别二:系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • Unix 基础知识 @[执行新程序, 打开文件, 读取文件, 分配存储区, 获取当前时间等, 应用程序, shel...
    JamesPeng阅读 935评论 1 2
  • 1. 概述 《UNIX环境高级编程》介绍的是不同版本的Unix操作系统提供的服务。那具体指的是哪些服务呢?首先,需...
    伤口不该结疤阅读 5,269评论 6 54
  • 一切可以妥当的一定会妥当,准备迎接奇迹! 今天开会本来只邀请我一人参加的,但是领导加了其他同事一起参加,一开始我感...
    belivePossible阅读 93评论 0 0
  • 亲子日记第142篇,2018年2月16日,星期五,天气晴。 今天是大年初一,首先向我认识的和认识我的人拜年了!祝大...
    海内存知己_bd9e阅读 192评论 0 2