c++高性能服务器开发01-环境搭建,相关基础概念,Linux系统相关函数

2023-05-16

1.安装Ubuntu18

  1. openssh-server
  2. net-tools
  3. pwd
  4. ls
  5. vscode
    1. 插件:remote
    2. c++
    3. 配置公钥
      1. windows 公钥复制到Linux的./ssh/authorized_keys
      2. ssh-keygen
  6. xshell
  7. xpt

2.gcc

  1. 安装
  2. 工作流程
    1. 源代码.c .h --预处理器(删除注释 宏处理替换,投文件展开)—处理后源代码.i – 编译器–汇编代码.s(汇编代码)–汇编器–目标代码.o–连接器 --可执行文件.out.exe
    2. gcc test.c -E -o test.i、
    3. gcc test.i -S -o test.s
    4. gcc test.s -o test.o

3.g++

类似gcc
g++ test.c -o test

4.gcc和g++的区别

gcc 和 g++都是GNU(组织)的一个编译器。

  • 误区一:gcc
    二只能编译c代码,g++只能编译c++代码。两者都可以,请注意:
    后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序
    后缀为.cpp的,两者都会认为是C++程序,C++的语法规则更加严谨

    编译阶段,g++会调用gcc,对于C++代码,两者是等价的,但是因为gcc
    命令不能自动和C++程序使用的库联接,所以通常用g++来完成链接,为了统一起见,干脆编译/链接统统用g++了,这就给人一种错觉,好像cpp程序只能用g++似的

  • 误区二:gcc
    实际上,这个宏只是标志着编译器将会把代码按C还是C++语法来解释
    如上所述,如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则就是已定义

  • 误区三:编译只能用gcc,链接只能用g++
    严格来说,这句话不算错误,但是它混淆了概念,应该这样说:编译可以用gcc/g++,而链接可以用g++或者gcc-1stdc++。
    gcc命令不能自动和C++程序使用的库联接,所以通常使用g++来完成联接。
    但在编译阶段,g++会自动调用gcc,二者等价

5. gcc编译选项

参数描述
-E预处理指定的源文件,不进行编译
-S编译指定的源文件,但是不进行汇编
-c编译、汇编指定的源文件,但是不进行链接
-o[file1] [file2] / [file2] -o [file1] 将文件file2编译成可执行文件file1
-Idirectory 指定 include 包含文件的搜索目录
-g在编译的时候,生成调试信息,该程序可以被调试器调试
-D在程序编译的时候,指定一个宏 gcc test02.c -o test -DDEBUG
-w不生成任何警告信息
-Wall生成所有警告信息
-Onn的取值范围:0~3。编译器的优化选项的4个级别,-o0表示没有优化,-o1为缺省值,-o3优化级别最高
-l在程序编译的时候,指定使用的库
-L指定编译的时候,搜索的库的路径。
-fPIC/fpic生成与位置无关的代码
-shared生成共享目标文件,通常用在建立共享库时
-std指定c方言,如:-std=c99,gcc默认的方言是GNU C

6.静态库制作

  1. 库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。

    库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。

    库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。
    库的好处:1.代码保密2.方便部署和分发

  2. 命名规则:
    Linux:libxxx.a
    lib:前缀(固定)
    xxx:库的名字,自己起
    .a:后缀(固定)
    Windows:libxxx.lib

  3. 静态库的制作:
    gcc获得.o文件 -c
    将.o文件打包,使用ar工具(archive)
    ar rcs libxxx.a xxx.o xxx.o
    r - 将文件插入备存文件中
    C - 建立备存文件
    s - 索引

  4. 使用

    1. gcc -c add.c sub.c mult.c div.c -I …/include/ 编译生成.o
    2. ar rcs libcalc.a add.o sub.o mult.o div.o 生成libcal.a静态库文件
    3. gcc main.c -o app -I ./include/calc -L ./lib -l calc

7.动态库的制作和使用

  1. 命名规则:
    Linux:libxxx.so
    lib:前缀(固定)
    xxx:库的名字,自己起
    .so:后缀(固定)
    在Linux下是一个可执行文件
    Windows:libxxx.dll
  2. 动态库的制作:
    gcc -c 得到.o文件,得到和位置无关的代码
    gcc -c -fpic / -fPIC a.c b.c
    gcc得到动态库
    gcc -shared a.o b.o -o libcalc.so
  3. 指定头文件目录和动态库文件目录编译得目标文件gcc main.c -o main -I include/ -L lib/ -l calc
  4. 配置动态库环境变量路径(仅在终端内生效):export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/绝对路径
  5. 查看环境变量:echo $ LD _ LIBRARY _ PATH
  6. 查看依赖ldd main
  7. 用户级环境变量配置:
    1. 在家目录下 编辑.bashrc文件
    2. source .bashrc 使生效
  8. 系统级别环境变量配置
    1. 编辑 /etc/profile 文件
    2. source .bashrc 使生效
  9. 修改/etc/ld.so.cache文件
    1. 间接修改 编辑/etc/ld.so.conf
    2. 将路径直接加入
    3. 更新 sudo ldconfig
  10. 不建议在把库文件放入/lib目录

8.库的工作原理

  1. 静态库:GCC进行链接时,会把静态库中代码打包到可执行程序中
  2. 动态库:GCC进行链接时,动态库的代码不会被打包到可执行程序中
  3. 程序启动之后,动态库会被动态加载到内存中,通过ldd(list dynamic
    dependencies)命令检查动态库依赖关系
  4. 如何定位共享库文件呢?
    当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT_RPATH段 -> 环境变量LD_LIBRARY_PATH —> /etc/ld.so.cache文件列表 —> /lib/, /usr/lib目录找到库文件后将其载入内存。

9.静态库和动态库的对比

1.在这里插入图片描述

  1. 静态库

    1. 优点:
      静态库被打包到应用程序中加载速度快
      发布程序无需提供静态库,移植方便
    2. 缺点:
      消耗系统资源,浪费内存
      更新、部署、发布麻烦
  2. 动态库

    1. 优点:
      可以实现进程间资源共享(共享库)
      更新、部署、发布简单
      可以控制何时加载动态库
    2. 缺点:
      加载速度比静态库慢
      发布程序时需要提供依赖的动态库

10.makefile

  1. 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为Makefile文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。Makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释Makefile文件中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如 Delphi 的 make, Visual C++的 nmake, Linux 下 GNU的make。

  2. 命名规则

    1. makefile 或Makefile

    2. makefile规则

      1. 一个文件中可以有一个或多个规则

      2. 目标…:依赖…

        ​ 命令(shell命令)

        ​ …

        1. 目标:最终要生成的文件(伪目标除外)
        2. 依赖:生成目标所需要的文件或是目标
        3. 命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
      3. 其他规则为第一规则服务

  3. makefile文件编写

  4. makefile工作原理

  5. 工作原理

    1. 命令在执行之前,需要先检查规则中的依赖是否存在

      1. 如果存在,执行命令
      2. 如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令
    2. 检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间

      1. 如果依赖的时间比目标的时间晚,需要重新生成目标
      2. 如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行
  6. 变量

    1. 自定义变量
      变量名=变量值 var=hello
    2. 预定义变量
      AR:归档维护程序的名称,默认值为ar
      CC:C编译器的名称,默认值为cc
      CXX:C++编译器的名称,默认值为g++
      $@:目标的完整名称
      $<:第一个依赖文件的名称
      $^:所有的依赖文件
    3. 获取变量的值
      $(变量名)
    4. 模式匹配
      1. %.o:%.c
        :通配符,匹配一个字符串
        -两个%匹配的是同一个字符串
      2. %.o:%.c
        gcc -c $< -o $@
  7. 函数

    1. $(wildcard PATTERN...)//函数名 函数参数

      1. 功能:获取指定目录下指定类型的文件列表
      2. 参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
      3. 返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
      4. 示例:
        $(wildcard *.c ./sub/*.c)
        返回值格式:a.c b.c c.c d.c e.c f.c
    2. $(patsubst <pattern>,<replacement>,<text>)

      1. 功能:查找<text>中的单词(单词以“空格”、“Tab"或“回车”换行“分隔)是否符合模式,如果匹配的话,则以替换。
      2. 可以包括通配符%,表示任意长度的字串。如果中也包含%,那么,中的这个%将是中的那个%
        所代表的字串。(可以用\来转义,以%来表示真实含义的“字符)
      3. 返回:函数返回被替换过后的字符串
      4. 示例:
        $(patsubst %.c,%.o,x.c bar.c)
        返回值格式:x.o bar.o
    3. clean函数

      1. clean:

        ​ rm $(objs) -f

      2. make clean 不能有clean文件

        1. 在之前加.PHONY:clean声明不生成clean文件

11. GDB调试

  1. 通常,在为调试而编译时,我们会()关掉编译器的优化选项(-0),并打开调试选项(-g)。另外,——Wa11在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的BUG。
    gcc -g -Wall program.c -o program

  2. -g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件。

  3. GDB命令

    1. 启动和退出
      gdb 可执行程序
      quit

      给程序设置参数/获取设置参数
      set args 10 20
      show args

      GDB使用帮助
      help

      查看当前文件代码
      list/l (从默认位置显示)
      list/l 行号(从指定的行显示)
      list/l 函数名(从指定的函数显示)

      查看非当前文件代码
      list/l 文件名:行号
      list/l 文件名:函数名

      设置显示的行数
      show list/listsize
      set list/listsize 行数

    2. 设置断点
      b/break行号
      b/break函数名
      b/break文件名:行号
      b/break文件名:函数

      查看断点
      i/info b/break

      删除断点
      d/del/delete 断点编号

      设置断点无效
      dis/disable 断点编号

      设置断点生效
      ena/enable 断点编号

      设置条件断点(一般用在循环的位置)
      b/break 10 if i==5

    3. 运行GDB程序
      start(程序停在第一行)
      run(遇到断点才停)
      继续运行,到下一个断点停
      c/continue
      向下执行一行代码(不会进入函数体)
      n/next
      变量操作
      p/print变量名(打印变量值)
      ptype变量名(打印变量类型)

      向下单步调试(遇到函数进入函数体)
      s/step
      finish(跳出函数体)
      自动变量操作
      display num(自动打印指定变量的值)
      i/info display
      undisplay编号
      其它操作
      set var 变量名=变量值
      until(跳出循环)

12. 标准C库IO函数和Linux系统IO函数对比

​

13. 虚拟地址空间

在这里插入图片描述

14.文件描述符

在这里插入图片描述

15. Linux系统IO函数

1. 文件打开关闭open close

int open(const char *pathname, int flags);//文件路径 ,权限,返回文件描述符,失败返回-1
int open(const char *pathname, int flags, mode_t mode);//mode 八进制数:创建的新文件操作权限
int close(int fd);关闭文件
perror,打印错误描述
umask 权限掩码 默认0002

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){
//创建一个新的文件
	int fd = open("create.txt",0_RDWR|O_CREAT,0777);
	if(fd==-1)
	{
		perror("open");
	}
close(fd);
 }

2. 文件读写read write

ssize_t read(int fd, void *buf, size_t count);//文件描述符,读取数据存放的地方数组地址,数组大小,返回值:读取成功返回读取字节数,失败返回-1
ssize_t write(int fd, const void *buf, size_t count);

/*  
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
   - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
   - buf:需要读取数据存放的地方,数组的地址(传出参数)
   - count:指定的数组的大小
返回值:
   - 成功:
       >0: 返回实际的读取到的字节数
       =0:文件已经读取完了
   - 失败:-1 ,并且设置errno

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
   - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
   - buf:要往磁盘写入的数据,数据
   - count:要写的数据的实际的大小
返回值:
   成功:实际写入的字节数
   失败:返回-1,并设置errno
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {

  // 1.通过open打开english.txt文件
  int srcfd = open("english.txt", O_RDONLY);
  if(srcfd == -1) {
      perror("open");
      return -1;
  }

  // 2.创建一个新的文件(拷贝文件)
  int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
  if(destfd == -1) {
      perror("open");
      return -1;
  }

  // 3.频繁的读写操作
  char buf[1024] = {0};
  int len = 0;
  while((len = read(srcfd, buf, sizeof(buf))) > 0) {
      write(destfd, buf, len);
  }

  // 4.关闭文件
  close(destfd);
  close(srcfd);
         return 0;
  }

3. 文件指针偏移fseek

off_t lseek(int fd, off_t offset, int whence);

/*  
 标准C库的函数
 #include <stdio.h>
 int fseek(FILE *stream, long offset, int whence);

 Linux系统函数
 #include <sys/types.h>
 #include <unistd.h>
 off_t lseek(int fd, off_t offset, int whence);
参数:
  - fd:文件描述符,通过open得到的,通过这个fd操作某个文件
  - offset:偏移量
  - whence:
      SEEK_SET
          设置文件指针的偏移量
      SEEK_CUR
          设置偏移量:当前位置 + 第二个参数offset的值
      SEEK_END
          设置偏移量:文件大小 + 第二个参数offset的值
返回值:返回文件指针的位置  
作用:
  1.移动文件指针到文件头
  lseek(fd, 0, SEEK_SET);

  2.获取当前文件指针的位置
  lseek(fd, 0, SEEK_CUR);
  3.获取文件长度
  lseek(fd, 0, SEEK_END);

  4.拓展文件的长度,当前文件10b, 110b, 增加了100个字节
  lseek(fd, 100, SEEK_END)
  注意:需要写一次数据

*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {

 int fd = open("hello.txt", O_RDWR);

 if(fd == -1) {
     perror("open");
     return -1;
 }

 // 扩展文件的长度
 int ret = lseek(fd, 100, SEEK_END);
 if(ret == -1) {
     perror("lseek");
     return -1;
 }

 // 写入一个空数据
 write(fd, " ", 1);

 // 关闭文件
 close(fd);

 return 0;
} 

4. 获取文件相关的信息stat

int stat ( const char * pathname , struct stat * statbuf ) ;
int lstat ( const char * pathname , struct stat * statbuf ) ;

/*
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
  作用:获取一个文件相关的一些信息
  参数:
      - pathname:操作的文件的路径
      - statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
      文件大小   块   类型   设备  权限   Inode   硬链接  Uid  Gid  时间戳
      
  返回值:
      成功:返回0
      失败:返回-1 设置errno

int lstat(const char *pathname, struct stat *statbuf);//获取软链接信息
  参数:
      - pathname:操作的文件的路径
      - statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
  返回值:
      成功:返回0
      失败:返回-1 设置errno

struct stat {
	dev_t   st_dev;//文件的设备编号
	ino_t   st_ino;//节点
	mode_t   st mode;//文件的类型和存取的权限
	nlink_t   st_nlink;//连到该文件的硬连接数目
	uid_t  st_uid; //用户ID
	gid_t   st_gid;//组ID
	dev_t   st_rdev;//设备文件的设备编号
	off_t  st_size;//文件字节数(文件大小)
	blksize_t  st_blksize;//块大小
	blkcnt_t  st_blocks;//块数
	time_t  st_atime;//最后一次访问时间
	time_t  st_mtime;//最后一次修改时间
	time_t  st_ctime; //最后一次改变时间(指属性)
};

*/

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main() {

  struct stat statbuf;

  int ret = stat("a.txt", &statbuf);

  if(ret == -1) {
      perror("stat");
      return -1;
  }

  printf("size: %ld\n", statbuf.st_size);
   return 0;
  }

在这里插入图片描述

//案例

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>

// 模拟实现 ls -l 指令
// -rw-rw-r-- 1 nowcoder nowcoder 12 12月  3 15:48 a.txt
int main(int argc, char * argv[]) {

   // 判断输入的参数是否正确
   if(argc < 2) {
       printf("%s filename\n", argv[0]);
       return -1;
   }

   // 通过stat函数获取用户传入的文件的信息
   struct stat st;
   int ret = stat(argv[1], &st);
   if(ret == -1) {
       perror("stat");
       return -1;
   }

    // 获取文件类型和文件权限
  char perms[11] = {0};   // 用于保存文件类型和文件权限的字符串

  switch(st.st_mode & S_IFMT) {
      case S_IFLNK:
          perms[0] = 'l';
          break;
      case S_IFDIR:
          perms[0] = 'd';
          break;
      case S_IFREG:
          perms[0] = '-';
          break; 
      case S_IFBLK:
          perms[0] = 'b';
          break; 
      case S_IFCHR:
          perms[0] = 'c';
          break; 
      case S_IFSOCK:
          perms[0] = 's';
          break;
      case S_IFIFO:
          perms[0] = 'p';
          break;
      default:
          perms[0] = '?';
          break;
  }

  // 判断文件的访问权限

  // 文件所有者
  perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
  perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
  perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';

  // 文件所在组
  perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
  perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
  perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';

  // 其他人
  perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
  perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
  perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';

  // 硬连接数
  int linkNum = st.st_nlink;

  // 文件所有者
  char * fileUser = getpwuid(st.st_uid)->pw_name;

  // 文件所在组
  char * fileGrp = getgrgid(st.st_gid)->gr_name;

  // 文件大小
  long int fileSize = st.st_size;

  // 获取修改的时间
  char * time = ctime(&st.st_mtime);

  char mtime[512] = {0};
  strncpy(mtime, time, strlen(time) - 1);

  char buf[1024];
  sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);

  printf("%s\n", buf);

  return 0;
}

4. 文件属性操作函数

int access (const char *pathname, int mode);//判断权限
int chmod(const char*filename,int mode);//修改权限
int chown(const char*path,uid_t owner,gid_t group);//设置文件所有者
int truncate(const char*path,off_t length);//扩展文件

/*
     #include <unistd.h>
     int access(const char *pathname, int mode);
         作用:判断某个文件是否有某个权限,或者判断文件是否存在
         参数:
             - pathname: 判断的文件路径
             - mode:
                 R_OK: 判断是否有读权限
                 W_OK: 判断是否有写权限
                 X_OK: 判断是否有执行权限
                 F_OK: 判断文件是否存在
         返回值:成功返回0, 失败返回-1
 */
 
 #include <unistd.h>
 #include <stdio.h>
 
 int main() {
 
     int ret = access("a.txt", F_OK);
     if(ret == -1) {
         perror("access");
     }
 
     printf("文件存在!!!\n");
 
     return 0;
 }
        ///
/*
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
    修改文件的权限
    参数:
        - pathname: 需要修改的文件的路径
        - mode:需要修改的权限值,八进制的数
    返回值:成功返回0,失败返回-1

*/
#include <sys/stat.h>
#include <stdio.h>
int main() {

int ret = chmod("a.txt", 0777);

if(ret == -1) {
    perror("chmod");
    return -1;
}

return 0;
}

/*
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
    作用:缩减或者扩展文件的尺寸至指定的大小
    参数:
        - path: 需要修改的文件的路径
       - length: 需要最终文件变成的大小
   返回值:
        成功返回0, 失败返回-1
*/

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>

int main() {
     int ret = truncate("b.txt", 5);

if(ret == -1) {
	perror("truncate");
	return -1;
}
	return 0;
}

5. 目录操作函数

int mkdir (const char *pathname, mode_t mode);//创建目录
int rmdir(const char *pathname);//删除
int rename(const char*oldpath,const char*newpath);//修改name
int chdir(const char *path);//切换到目录
char*getcwd(char*buf,size_t size);//获取绝对路径buf以及空间大小。

/*
   #include <sys/stat.h>
   #include <sys/types.h>
   int mkdir(const char *pathname, mode_t mode);
       作用:创建一个目录
       参数:
           pathname: 创建的目录的路径
           mode: 权限,八进制的数
       返回值:
           成功返回0, 失败返回-1
*/

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>

int main() {

   int ret = mkdir("aaa", 0777);

   if(ret == -1) {
       perror("mkdir");
       return -1;
   }

   return 0;
}
  ///
/*
    #include <stdio.h>
    int rename(const char *oldpath, const char *newpath);

*/
#include <stdio.h>

int main() {

    int ret = rename("aaa", "bbb");

    if(ret == -1) {
        perror("rename");
        return -1;
    }

    return 0;
}
//
/*

#include <unistd.h>
int chdir(const char *path);
  作用:修改进程的工作目录
      比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder
  参数:
      path : 需要修改的工作目录

#include <unistd.h>
char *getcwd(char *buf, size_t size);
  作用:获取当前工作目录
  参数:
      - buf : 存储的路径,指向的是一个数组(传出参数)
      - size: 数组的大小
  返回值:
      返回的指向的一块内存,这个数据就是第一个参数

*/
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

int main() {

   // 获取当前的工作目录
   char buf[128];
   getcwd(buf, sizeof(buf));
   printf("当前的工作目录是:%s\n", buf);

   // 修改工作目录
   int ret = chdir("/home/nowcoder/Linux/lesson13");
   if(ret == -1) {
       perror("chdir");
       return -1;
   } 

   // 创建一个新的文件
   int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);
   if(fd == -1) {
       perror("open");
       return -1;
   }

   close(fd);

   // 获取当前的工作目录
   char buf1[128];
   getcwd(buf1, sizeof(buf1));
   printf("当前的工作目录是:%s\n", buf1);
   
   return 0;
}

6. 目录遍历函数

DIR *opendir (const char *name);
struct dirent *readdir (DIR *dirp);
int closedir (DIR *dirp);

/*
// 打开一个目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
   参数:
       - name: 需要打开的目录的名称
   返回值:
       DIR * 类型,理解为目录流
       错误返回NULL
       
// 读取目录中的数据
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
- 参数:dirp是opendir返回的结果
- 返回值:
    struct dirent,代表读取到的文件的信息
    读取到了末尾或者失败了,返回NULL
struct dirent{
//此目录进入点的inode
ino_t d ino;
//目录文件开头至此目录进入点的位移
off_t d_off;
//d_name的长度,不包含NULL字符
unsigned short int d_reclen;
//d_name所指的文件类型
unsigned char d_type;
//文件名
char d_name[256];
};
文件类型     
d type
 DT_BLK-块设备
 DT_CHR-字符设备
 DT_DIR-目录
 DT_LNK-软连接
 DT_FIFO-管道
 DT_REG-普通文件
 DT_SOCK-套接字
 DT_UNKNOWN-未知

​// 关闭目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
*/
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int getFileNum(const char * path); // 读取某个目录下所有的普通文件的个数
int main(int argc, char * argv[]) {
​         
​ if(argc < 2) {
  printf("%s path\n", argv[0]);
  return -1;
}int num = getFileNum(argv[1]);
  printf("普通文件的个数为:%d\n", num);return 0;
}// 用于获取目录下所有普通文件的个数
int getFileNum(const char * path) {

// 1.打开目录
DIR * dir = opendir(path);

if(dir == NULL) {
 	perror("opendir");
 	exit(0);
}struct dirent *ptr;// 记录普通文件的个数int total = 0;while((ptr = readdir(dir)) != NULL) {// 获取名称char * dname = ptr->d_name;
// 忽略掉. 和..
 if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
 continue;
 }

// 判断是否是普通文件还是目录
if(ptr->d_type == DT_DIR) {
// 目录,需要继续读取这个目录
char newpath[256];
sprintf(newpath, "%s/%s", path, dname);
total += getFileNum(newpath);
}

if(ptr->d_type == DT_REG) {
// 普通文件
total++;
}
}

// 关闭目录
closedir(dir);

return total;
}

7.复制文件描述符 dup dup2

int dup (int oldfd) ;复制文件描述符
int dup2(int oldfd, int newfd);重定向文件描述符

 /*
 #include <unistd.h>
  int dup(int oldfd);
      作用:复制一个新的文件描述符
      fd=3, int fd1 = dup(fd),
      fd指向的是a.txt, fd1也是指向a.txt
      从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符
*/
     
     #include <unistd.h>
     #include <stdio.h>
     #include <fcntl.h>
     #include <sys/types.h>
     #include <sys/stat.h>
     #include <string.h>
     
     int main() {
              int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
 
     int fd1 = dup(fd);
 
     if(fd1 == -1) {
         perror("dup");
         return -1;
     }
 
     printf("fd : %d , fd1 : %d\n", fd, fd1);
 
     close(fd);
 
     char * str = "hello,world";
     int ret = write(fd1, str, strlen(str));
     if(ret == -1) {
         perror("write");
         return -1;
     }
 
     close(fd1);
 
     return 0;
 }
 //
  /*
  #include <unistd.h>
  int dup2(int oldfd, int newfd);
      作用:重定向文件描述符
      oldfd 指向 a.txt, newfd 指向 b.txt
      调用函数成功后:n 
      ewfd 和 b.txt 做close, newfd 指向了 a.txt
      oldfd 必须是一个有效的文件描述符
      oldfd和newfd值相同,相当于什么都没有做
  */
  #include <unistd.h>
  #include <stdio.h>
  #include <string.h>
  #include <sys/stat.h>
  #include <sys/types.h>
  #include <fcntl.h>
  
  int main() {
  
      int fd = open("1.txt", O_RDWR | O_CREAT, 0664);
      if(fd == -1) {
          perror("open");
          return -1;
      }
  
      int fd1 = open("2.txt", O_RDWR | O_CREAT, 0664);
      if(fd1 == -1) {
          perror("open");
          return -1;
      }
  
      printf("fd : %d, fd1 : %d\n", fd, fd1);
  
      int fd2 = dup2(fd, fd1);
      if(fd2 == -1) {
          perror("dup2");
          return -1;
      }
  
      // 通过fd1去写数据,实际操作的是1.txt,而不是2.txt
      char * str = "hello, dup2";
      int len = write(fd1, str, strlen(str));
  
      if(len == -1) {
          perror("write");
          return -1;
      }
  
      printf("fd : %d, fd1 : %d, fd2 : %d\n", fd, fd1, fd2);
  
      close(fd);
      close(fd1);
  
      return 0;
  }

8. fcntl文件描述符操作

int fcntl (int fd, int cmd, ... /* arg */ );
复制文件描述符
设置/获取文件的状态标志

 /*
 
     #include <unistd.h>
     #include <fcntl.h>
 
     int fcntl(int fd, int cmd, ...);
     参数:
         fd : 表示需要操作的文件描述符
         cmd: 表示对文件描述符进行如何操作
             - F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
                 int ret = fcntl(fd, F_DUPFD);
 
             - F_GETFL : 获取指定的文件描述符文件状态flag
               获取的flag和我们通过open函数传递的flag是一个东西。
 
             - F_SETFL : 设置文件描述符文件状态flag
               必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
               可选性:O_APPEND, O_NONBLOCK
                 O_APPEND 表示追加数据
                 O_NONBLOCK 设置成非阻塞
         
         阻塞和非阻塞:描述的是函数调用的行为。
 */
 
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 
 int main() {
 
     // 1.复制文件描述符
     // int fd = open("1.txt", O_RDONLY);
     // int ret = fcntl(fd, F_DUPFD);
 
     // 2.修改或者获取文件状态flag
     int fd = open("1.txt", O_RDWR);
     if(fd == -1) {
         perror("open");
         return -1;
     }
 
     // 获取文件描述符状态flag
     int flag = fcntl(fd, F_GETFL);
     if(flag == -1) {
         perror("fcntl");
         return -1;
     }
     flag |= O_APPEND;   // flag = flag | O_APPEND
 
     // 修改文件描述符状态的flag,给flag加入O_APPEND这个标记
     int ret = fcntl(fd, F_SETFL, flag);
     if(ret == -1) {
         perror("fcntl");
         return -1;
     }
 
     char * str = "nihao";
     write(fd, str, strlen(str));
 
     close(fd);
 
     return 0;
 }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++高性能服务器开发01-环境搭建,相关基础概念,Linux系统相关函数 的相关文章

  • Cmakelists.txt 的基本框架

    执行 cmake 表示在当前目录下执行 cmake cmake 表示在前一级目录下执行 cmake make 在当前目录下执行 make 语法 1 设置 cmake 版本需求 cmake minimum required VERSION 2
  • UartAssist - 串口调试助手。

    由于项目需要用到串口 xff0c 所以我就找到一个简单易上手的串口调试助手 串口调试助手 1 助手界面 xff1a 2 设置串口 xff0c 点击 打开 3 设置发送区和接收区参数 4 输入发送内容 xff0c 点击 发送 即可
  • 网络摄像机rtsp地址详解。

    RTSP xff08 Real Time Streaming Protocol xff09 xff0c RFC2326 xff0c 实时流传输协议 xff0c 是TCP IP协议体系中的一个应用层协议 xff0c 由哥伦比亚大学 网景和Re
  • Qt 登陆界面实现

    简单的QT用户登录界面 一 项目描述 在登录界面输入用户名和密码正确之后才进入欢迎界面 用户名 xff1a xiaoxian 密码 xff1a 1240 二 效果图 三 源代码 loginform span class token punc
  • FFMPEG保存视频流数据至本地(rtsp转mp4)

    将rtsp流中的h264视频流在没解码之前获取下来 xff0c 并保存到本地文件mp4中的h264流中 xff0c h264 gt mp4 网络摄像机rtsp地址详解 流程图 xff1a 源码 xff1a span class token
  • Qt + FFmpeg实现播放器(FFmpeg可以解码的格式基本都可以播放)。

    一 开发环境的准备 Linux下移植ffmpeg开源库 二 代码实现播放功能 1 打开音视频流并获取音视频流信息 xff1b 2 查找视频流位置以及查找并打开视频解码器 xff1b 3 视频解码的同时处理图片像素数据 xff1b 4 最后要
  • SecureCRT 下的串口不能输入指令。

    1 在 SecureCRT 下的串口不能输入指令 解决方法 xff1a Session Options gt Connection gt Serial gt Flow Control xff0c 将原先默认选中的 RTS CTS取消掉即可
  • Qt实现简单密码登陆界面

    效果图 xff1a 代码实现 span class token macro property span class token directive hash span span class token directive keyword i
  • error: ‘uint8_t’,‘uint32_t’ does not name a type

    c 43 43 里用了c的代码 xff0c 确切的说 xff0c 是引用了c写的x264 h xff0c 结果报错了 xff1a 解决方法 xff1a span class token macro property span class t
  • gitlab 同时拉取整个项目

    一 xff1a 下载repo工具包 下载地址 xff1a GitHub NeutionWei repo unzip repo 刚下载的repo包解压 xff0c 其中的repo只是一个几百行的脚本 xff0c 需要repo init才可以获
  • CMakeLists.txt详解

    一 xff1a CMakeLists txt文件是cmake用来生成Makefile文件需要的一个描述编译链接的规则文件 学习cmake需要提前了解gcc等编译命令 xff0c 先来解释一条最简单的命令 gcc source c o bin
  • opencv估计两图的三维坐标变换矩阵

    cv estimateAffine3D MatFrom MatTo Transfrom inlier Transform得到的是重MatFrom到MatTo的变换矩阵 inlier给一个空矩阵就可以 MatFrom和MatTo都是点的矩阵
  • shell脚本详解

    通俗来讲shell脚本就是把shell命令放在一个 脚本 中 xff0c 脚本的第一行 xff01 bin bash 意思为这个脚本指定一款在 bin 下名叫bash的shell解释器 xff0c 来解释接下来的任何命令 xff0c 如果我
  • 车载以太网测试规范tc8下载地址

    网上只要搜到下载就要积分 xff0c VIP xff0c 其实他们也是从别处免费下载的 xff0c 拿到别处骗钱 xff0c 话不多说下载地址如下 xff1a Open Alliance 不用谢 xff01
  • ARP包解析及工作原理

    ARP数据包42字节 参照以下例子 xff1a 前12字节为以太网的目的地址 54 89 98 0f 2b be 和源地址 54 89 98 5b 5b 8a xff0c 当目的地址全为1时是以太网广播地址 xff0c 此时ARP还未建立缓
  • Jetson Xavier NX刷机安装Ubuntu20.04,配置CUDA,cuDNN,Pytorch等环境教程(英伟达官方源安装,理论适用其它Jetson设备)

    一 准备工作 硬件 xff1a Jetson Xavier NX开发板 xff08 笔者购入为带128g内存条的EMMC版 xff09 跳线帽 xff08 杜邦线 xff09 microUSB转USB数据线 电源线 软件 xff1a Ubu
  • Hadoop伪分布搭建完整步骤

    1 新建虚拟机配置网络并测试网络连接 1 鼠标单击左侧虚拟机名称 xff0c 接着单击菜单栏 编辑 xff0c 在下拉菜单中选择 虚拟网络适配器 xff0c 如图 1 2 20 所示 4 在打开的 虚拟网络编辑器 对话框 xff0c 单击
  • linux--top命令查看系统所有详情

    Linux系统可以通过top 命令查看系统的CPU 内存 运行时间 交换分区 执行的线程等信息 通过top命令可以有效的发现系统的缺陷出在哪里 是内存不够 CPU处理能力不够 IO读写过高 一 top命令的第一行 top 19 56 47
  • OPENMV巡线

    将openmv图片划分成三个ROI区域 import sensor image time lcd from pyb import UART from pyb import LED ROIS 61 0 0 160 40 0 6 0 40 16
  • C++学习笔记

    一 一些重要的常见知识点 1 函数的分文件编写 xff1a h的头文件 xff08 写函数声明 xff09 cpp的源文件 xff08 写函数功能实现 xff09 2 空指针和野指针 xff1a 0 255的内存是系统所占有的 96 int

随机推荐

  • 使用XTDrone遇到的问题的解决

    在使用XTDrone时 xff0c 遇到了px4包找不到的问题 xff1a RLException mavros posix sitl launch is neither a launch file in package 使用官方配置文档h
  • 树莓派书籍全方位推荐

    相关书籍 python编程篇1 Python硬件开发树莓派从入门到实践 内容简介作者简介 2 Python树莓派开发从入门到精通内容简介编辑推荐 3 树莓派Python编程入门与实战书籍简介 4 树莓派Python编程指南内容简介作者简介
  • 总结几个比较常用的数学公式(新手入门)

    合理的公式可以帮助我们优化代码 xff0c 比如可以减少遍历的次数 xff0c 减少思考的难度 xff0c 提高算法效率 xff0c 此文章将持续更新 一 换底公式 Logab 61 logxb logxa 换底公式虽然不常用 xff0c
  • 【Linux/C/C++】面试题总结

    1 static关键字的作用 答 xff1a 在C语言中 xff0c 局部变量不会在诞生时被编译器自动初始化 xff0c 且生命周期终止于该变量所在的函数结束时 通过使用static关键字修饰局部变量 xff0c 可以使编译器自动为其赋初始
  • 匿名上位机V7与stm32通信协议

    一 xff0c 通信介绍 1 通信帧格式介绍 为了适应多种数据类型的传输 xff0c 保证高效的通信效率 xff0c 所有数据的通信 xff0c 均需要遵守本通信帧格式 本格式在 确保通信高效 源码简单 可移植性高的基础上 xff0c 实现
  • 酒店管理系统( JAVA)

    最近在学JAVA的数组学完之后做了一个简易的酒店管理系统 xff0c 酒店管理系统应该包含三部分 xff0c 第一部分是我们酒店管理系统的主题 xff0c 第二部分是我们酒店里的信息 xff0c 第三部分则是我们的房间信息 xff0c 具体
  • Ubuntu20.04下使用Qt5.15.2编译qgc源码

    下载QGC源码 可以在QGC官网按照教程根据自己的需求来下载源码QGC git clone recursive j8 https github com mavlink qgroundcontrol git git submodule upd
  • #ROS通讯机制:参数服务器

    参数服务器修改小海龟背景色 1 进入工作空间的src目录新建工作包 lzw08 64 ubuntu span class token operator span span class token operator span cd ros w
  • 9.19 GoogLeNet

    GoogLeNet GoogLeNet在2014年ImageNet图像识别挑战赛中大放异彩虽然NiN现在基本上没有被使用了 xff0c 但是GoogLeNet现在还是大量地被使用GoogLeNet是第一次做到快100层卷积层 xff08 第
  • react路由参数传递

    react路由的三种传参方式 1 向路由组件传递params参数 参数传递 在注册路由时接收参数 注意这里后面时冒号在前面的 在要展示的组件内接收params参数 2 第二种 xff0c 利用search传递参数 向路由组件传递参数 这种方
  • 链队列(详解)--->数据结构、C++实现

    问题引入 在数据结构中 xff0c 队列也是一种重要的线性结构 xff0c 常和栈放在一起进行学习 队列分为多种类型 xff0c 常见的如循环队列 链队列等 xff0c 如果此时此刻你对 链队列 感到困惑 xff0c 那就继续看下去 xff
  • Windows11正版下载和Windows10正版下载安装教程

    Windows11正版下载和Windows10正版下载 下载链接 xff1a https www microsoft com zh cn software download windows11 Windows11下载官网连接 https w
  • 2022-03-30 VsCode中使用clangd插件的各种设置

    最近尝试clang编译c 43 43 xff0c 所以用了clangd插件代替mscpp插件 xff0c 其中有不少问题 xff0c 都是通过各种搜索 xff0c 各种猜 xff0c 才能完善 xff0c 记录一下 xff0c 以便广大同仁
  • [Ubuntu]安装ifconfig

    apt install net tools
  • python3对接微信小程序蓝牙

    39 39 39 Created on 2019年10月15日 64 author lg 39 39 39 from Crypto Cipher import AES from binascii import b2a hex a2b hex
  • docker--Dockerfile操作指令

    docker Dockerfile操作指令 文章目录 docker Dockerfile操作指令一 FROM指令1 基本概述2 用法3 说明4 关于FROM scratch 二 RUN指令1 基本概述2 用法3 说明 三 ENV指令1 基本
  • 【监控】k8s部署prometheus + grafana

    k8s以Deployment方式部署prometheus 43 grafana xff1a 主机说明 xff1a 系统ip角色cpu内存hostnameCentOS 7 8192 168 30 128master gt 61 2 gt 61
  • 多线程以及在PYQT中的使用

    1 多线程 简单来说就是可以用多线程同时执行多个程序 在python中 xff0c 我们用的是 threading库 这个库包含了线程的方法和其他配套方法 xff08 比如锁 xff09 似乎 concurrent库会更方便更安全 xff0
  • 简单平衡小车制作过程中遇到的问题

    本人最近做了一个平衡小车 xff0c 过程中遇到不少问题 xff0c 在这里总结一下 xff0c 可能也会帮助到大家 文章目录 前言一 嫖资料 xff0c 找教程二 小车结构三 电子元件的组装四 写程序时 xff08 改嫖到的程序 xff0
  • c++高性能服务器开发01-环境搭建,相关基础概念,Linux系统相关函数

    1 安装Ubuntu18 openssh servernet toolspwdlsvscode 插件 xff1a remotec 43 43 配置公钥 windows 公钥复制到Linux的 ssh authorized keysssh k