IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux系统编程】| 【02】系统调用、系统函数、库、系统错误 -> 正文阅读

[系统运维]【Linux系统编程】| 【02】系统调用、系统函数、库、系统错误

1、系统调用

系统调用是受控的内核入口;
【系统调用的运作方式之前,需要关注】:
- 系统调用将处理器从用户态切换到核心态,以便CPU访问受到保护的内核内存;
- 系统调用的组成是固定的,每个系统调用都由一个唯一的数字来标识;
- 每个系统调用可辅之以一套参数,对用户空间(进程的虚拟地址空间)与内核空间之间(相互)传递的信息加以规范;

【执行系统调用步骤】:
- 程序通过调用C语言函数库中的外壳函数,来发起系统调用;
- 外壳函数必须保证所有系统调用参数可用,通过堆栈传入外壳函数;
- 由于所有系统调用进入内核的方式都相同,内核需要区分每个函数调用;
- 外壳函数执行一条中断机器指令(int 0x80),引发处理器从用户态切换到核心态,并执行系统中断;
- 为响应中断,内核会调用system_call例程来处理;
	a)在内核栈中保存寄存器值;
	b)审核系统调用编号的有效;
	c)以系统调用编号对存放所有调用服务例程的列表(内核变量sys_call_table)进行索引发现并调用相应的系统调用服务例程,
		若系统调用服务例程带有参数,那么将首先检查参数的有效性;
		最后,该服务例程会将结果状态返回给system_call()例程。
	d)从内核栈中恢复各寄存器值,并将系统调用返回值置于栈中;
	e)返回至外壳函数,同时将处理器切换回用户态;
- 若系统调用有误,外壳函数会使用返回值来设置全局变量errno;

在这里插入图片描述

2、库函数

为了提供比底层系统调用更为方便的调用接口;

3、标准C语言函数库,GNU C语言函数库(glibc)

GNU C是Linux上最常用的实现;
	- 可直接运行glibc共享库文件来获取glibc版本;
	- 针对某个与glibc动态链接的可执行文件,运行ldd;在检查输出的库依赖性列表,便能发现glibc共享库的位置;

glibc定义两个常量:__GLIBC__和__GLIBC_MINOR__;供程序在编译时测试使用;

在这里插入图片描述
在这里插入图片描述

4、处理来自系统调用和库函数的错误

4.1 处理系统调用错误

系统调用失败时,会将全局整型变量errno设置为一个正值,以标识具体错误;
	- 若调用成功,errno不会被重置为0,故该变量值不为0,可能是之前调用失败造成的;
	- 在错误检查时,必须坚持首先检查函数的返回值是否表明调用出错,在检查errno确定错误原因;
	- 根据errno打印错误消息,提供库函数perror和strerror;

strerror

返回的字符串可以是静态分配;
void test_error() {
	FILE *f = fopen("file.txt", "r+");
	if(f != NULL){
		std::cout << "文件打开成功..." << std::endl;
	}else{
		perror("error open");
		exit(-1);
	}
}

在这里插入图片描述

4.2 处理来自库函数的错误

- 某些库函数返回错误信息的方式与系统调用完全相同,返回值为-1,并以errno号来表示具体错误;
- 某些库函数在出错时返回-1之外的其他值,仍会设置errno;
- 还有些函数不适用errno;

5、示例程序的注意事项

ename.h

#ifndef LINUX_TEST_ENAME_H
#define LINUX_TEST_ENAME_H
static char *ename[] = {
        /*  0   */ "",
        /*  1   */ "EPERM", "ENOENT", "ESRCH", "EIO", "EXIO", "E2BIG",
        /*  8   */ "ENOEXEC", "EBADF", "ECHILD", "EAGAIN/EWOULDBLOCK", "ENOMEM",
        /*  13  */ "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV",
        /*  19  */ "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE",
        /*  25  */ "ENOTTY", "ETXTBSY", "EFBIG",  "ENOSPC", "ESPIPE", "EROFS",
        /*  31  */ "EMLINK", "EPIPE", "EDOM", "ERANGE", "EDEADLK/EDEADLOCK",
        /*  36  */ "ENMAETOOLONG", "ENOLCK", "ENOSYS", "ENOTEMPTY", "ELPP", "",
        /*  42  */ "ENOMSG", "EIDRM", "ECHRNG", "EL2NSYNC", "EL3HLT", "EL3RST",
        /*  48  */  "ELNRNG", "EUNATCH", "ENOCSI", "EL2HLT", "EBADE", "EBADR",
        /*  54  */ "EXFULL", "ENOANO", "EBADRO", "EBADSLT", "", "EBFONT", "ENOSTR",
        /*  61  */ "ENODATA", "ETIME", "ENOSR", "ENONET", "ENOPKG", "EREMOTE",
        /*  67  */ "ENOLINK", "EADV", "ESRMNT", "ECOMM", "EPROTO", "EMULITIHOP",
        /*  73  */ "EDOTDOT", "EBADMSG", "EOVERFLOW", "ENOTUNIQ", "EBADFD",
        /*  78  */ "EREMCHG", "ELIBACC", "ELIBBAD", "ELIBSCN", "ELIBMAX",
        /*  83  */ "ELIBEXECC", "EILSEQ", "ERESTART", "ESTRPIPe", "EUSERS",
        /*  88  */ "ENOTSOCK", "EDESTADDRREQ", "EMSGSIZE", "EPROTOTYPE",
        /*  92  */ "ENOPROTOOPT", "EPROTONOSUPPORT", "ESOCKTNOSUPPORT",
        /*  95  */ "EOPNOTSUPP/ENOTSUP", "EPFNOSUPPORT", "EAFNOSUPPORT",
        /*  98  */ "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN", "ENETUNREACH",
        /*  102 */ "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS", "EISCONN",
        /*  107 */ "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS", "ETIMEDOUT",
        /*  111 */ "ECONNREFUSED", "EHOSTDOWN", "EHOSTUNREACH", "EALREADY",
        /*  115 */ "EINPROGRESS", "ESTALE", "EUCLEAN", "ENOTNAM", "ENAVAIL",
        /*  120 */ "EISNAM", "EREMOTEIO", "EDQUOT", "ENOMEDIUM", "EMEDIUMTYPE",
        /*  125 */ "ECANCELED", "ENOKEY", "EKEYEXPIRED", "EKEYREVOKED",
        /*  129 */ "EKEYREJECTED", "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL"
};
#define MAX_ENAME 132

#endif //LINUX_TEST_ENAME_H

error_function.h

#ifndef LINUX_TEST_ERROR_FUNCTION_H
#define LINUX_TEST_ERROR_FUNCTION_H

/**
 * @brief: 在标准错误设备上打印消息,类似printf的用法,
 *              但不能将终止换行符自动追加到尾部;
 *          打印与当前errno值对应的错误文本
 * */
void errMsg(const char *format, ...);

#ifdef __GNUC__
#define NORETURN __attribute__((__noreturn__))
#else
#define NORETURN
#endif

/**
 * @brief: 与errMsg类型,但会调用exit退出,若环境变量EF_DUMPCORE定义为非空字符串,
 *      则调用abort退出;
 * */
void errExit(const char *format, ...) NORETURN;

/**
 * @brief: 类似errExit函数,但打印消息前,不会刷新标准输出;
 *          使用_exit()终止进程,略去对stdio缓冲区的刷新
 *          以及对退出处理程序的调用;
 * */
void err_exit(const char *format, ...) NORETURN;

/**
 * @brief: 主要用来处理线程中的错误
 * */
void errExitEN(int errnum, const char *format, ...) NORETURN;

/**
 * @brief: 诊断一般性错误,包括为设置errno的库函数错误
 * */
void fatal(const char *format, ...) NORETURN;

/**
 * @brief: 用来诊断命令行参数使用方面的错误
 * */
void usageErr(const char *format, ...) NORETURN;
void cmdLineErr(const char *format, ...) NORETURN;

#endif //LINUX_TEST_ERROR_FUNCTION_H

get_num.h

#ifndef LINUX_TEST_GEI_NUM_H
#define LINUX_TEST_GEI_NUM_H

#define GN_NONNEG 01
#define GN_GT_O 02

#define GN_ANY_BASE 0100
#define GN_BASE_8 0200
#define GN_BASE_16 0400

long getLong(const char *arg, int flags, const char *name);
int getInt(const char *arg, int flags, const char *name);

#endif //LINUX_TEST_GEI_NUM_H

tlpi_hdr.h

#ifndef LINUX_TEST_TLPI_HDR_H
#define LINUX_TEST_TLPI_HDR_H

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <algorithm>

#include "error_function.h"

using namespace std;


#endif //LINUX_TEST_TLPI_HDR_H

error_function.cpp

#include <stdarg.h>
#include <stdio.h>
#include "error_function.h"
#include "tlpi_hdr.h"
#include "ename.h"



/**
 * exit和_exit和abort的区别
 * */
static void terminate(bool useExit3){
    char *s;
    s = getenv("EF_DUMPCORE");
    /* 判断是否有定义EF_DUMPCORE */
    if(s != NULL && *s != '\0')
        abort();
    else if(useExit3)
        exit(EXIT_FAILURE);
    else
        _exit(EXIT_FAILURE);
}

static void outputError(bool useErr, int err, bool flushStdout,
                        const char *format, va_list ap) {
#define BUF_SIZE 500
    char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE];

    /* 将格式化数据从变量参数列表写入缓冲区 */
    vsnprintf(userMsg, BUF_SIZE, format, ap);

    /* 将错误消息格式化输出到errText */
    if(useErr)
        snprintf(errText, BUF_SIZE, " [%s %s]",
                 (err > 0 && err <= MAX_ENAME) ?
                 ename[err] : "?UNKNOWN?", strerror(err));
    else
        snprintf(errText, BUF_SIZE, ":");

    snprintf(buf, BUF_SIZE, "ERROR%s %s\n", errText, userMsg);
    if(flushStdout)
        fflush(stdout);
    fputs(buf, stderr);
}

void errMsg(const char *format, ...) {
    va_list argList;
    int savedErrno;
    savedErrno = errno;

    va_start(argList, format);
    outputError(true, errno, true, format, argList);
    va_end(argList);

    errno = savedErrno;
}

void errExit(const char *format, ...){
    va_list argList;

    va_start(argList, format);
    outputError(true, errno, true, format, argList);
    va_end(argList);

    terminate(true);
}

void err_exit(const char *format, ...) {
    va_list argList;

    va_start(argList, format);
    outputError(true, errno, false, format, argList);
    va_end(argList);

    terminate(false);
}

void errExitEN(int errnum, const char *format, ...){
    va_list argList;

    va_start(argList, format);
    outputError(true, errnum, true, format, argList);
    va_end(argList);

    terminate(true);
}

void fatal(const char *format, ...) {
    va_list argList;

    va_start(argList, format);
    outputError(true, 0, true, format, argList);
    va_end(argList);

    terminate(true);
}

void usageErr(const char *format, ...) {
    va_list argList;

    fflush(stdout);
    fprintf(stderr, "Usage: ");

    va_start(argList, format);
    vfprintf(stderr, format, argList);
    va_end(argList);

    fflush(stderr);
    exit(EXIT_FAILURE);
}

void cmdLineErr(const char *format, ...) {
    va_list argList;

    fflush(stdout);
    fprintf(stderr, "Command-line usage error: ");
    vfprintf(stderr, format, argList);
    va_end(argList);

    fflush(stderr);
    exit(EXIT_FAILURE);
}

get_num.cpp

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "get_num.h"

static void gnFail(const char *fname, const char *msg, const char *arg, const char *name) {
    fprintf(stderr, "%s error", fname);
    if(name != NULL)
        fprintf(stderr, " (in %s)", name);
    fprintf(stderr, ": %s\n", msg);
    if(arg != NULL && *arg != '\0')
        fprintf(stderr, "    offending text: %s\n", arg);
    exit(EXIT_FAILURE);
}

static long getNum(const char *fname, const char *arg, int flags, const char *name) {
    long res;
    char *endptr;
    int base;

    if(arg == NULL || *arg == '\0')
        gnFail(fname, "null or empty string", arg, name);
    base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8 :
                                       (flags & GN_BASE_16) ? 16 : 10;
    errno = 0;
    res = strtol(arg, &endptr, base);
    if(errno != '\0')
        gnFail(fname, "nonnumeric characters", arg, name);

    if((flags & GN_GT_O) && res < 0)
        gnFail(fname, "negative value not allowed", arg, name);
    if((flags & GN_GT_O) && res <= 0)
        gnFail(fname, "value must be > 0", arg, name);

    return res;
}

long getLong(const char *arg, int flags, const char *name) {
    return getNum("getLong", arg, flags, name);
}

int getInt(const char *arg, int flags, const char *name) {
    long res;

    res = getNum("getInt", arg, flags, name);
    if(res > INT_MAX || res < INT_MAX)
        gnFail("getInt", "integer out of range", arg, name);
    return (int)res;
}

6、系统数据类型

在这里插入图片描述

在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-06-08 19:16:18  更:2022-06-08 19:19:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:35:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码