• Linux系统编程(1)


    父子进程通过两个管道进行通信。

     

    1. 伪代码
    2. #include
    3. void client(int, int), server(int, int);
    4. int main(int argc, char** argv) {
    5. int pipe1[2], pipe2[2];
    6. pid_t childpid;
    7. Pipe(pipe1);
    8. Pipe(pipe2);
    9. if ((childpid == Fork()) == 0) {
    10. // child
    11. Close(pipe1[1]);
    12. Close(pipe2[0]);
    13. server(pipe1[0], pipe2[1]);
    14. exit(0);
    15. }
    16. // parent
    17. Close(pipe1[0]);
    18. Close(pipe2[1]);
    19. client(pipe2[0], pipe1[1]);
    20. Waitpid(childpid, NULL, 0);
    21. exit(0);
    22. }

    open()函数

    1. int fd;
    2. fd = open("test.txt", O_RDONLY);
    3. if (fd == -1) {
    4. //错误
    5. }
    6. ==========================================
    7. int fd;
    8. //如果文件存在,则截断文件,文件不存在,则创建,并且后面指定了文件的权限
    9. fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);

    creat()函数

    1. #include
    2. #include
    3. #include
    4. int fd;
    5. fd = creat(file, 0644);
    6. if (fd == -1)
    7. fd = open(file, O_RWONLY | O_CREAT | O_TRUNC, 0644);
    8. 是一样的效果。

    read()函数

    1. #include
    2. ssize_t read(int fd, void* buf, size_t len);
    3. 从文件描述符fd对应当前的位置读取len字节到buf中,执行成功返回读取的字节数,失败返回-1并设置errno,
    4. ssize_t ret;
    5. while(len != 0 && (ret = read(fd, buf, len)) != 0) {
    6. if (ret == -1) {
    7. if (errno == EINTR) continue;
    8. perror("read");
    9. break;
    10. }
    11. len -= ret;
    12. buf += ret;
    13. }

     lseek()查找文件位置

    1. #include
    2. #include
    3. off_t lseek (int fd, off_t pos, int origin);

    origin参数主要有一下值:

    SEEK_CUR:fd的当前文件位置被设置为当前值+pos(其值可是负数,0,正数),pos为零时,返回当前位置。

    SEEK_END:fd的当前位置被设定为文件的当前长度+pos(其值可是负数,0,正数),pos为零时,当前位置为文件的末端。

    SEEK_SET:fd的当前位置被设置为pos,pos为零时,偏移值为文件的开头。

    此调用执行成功时,返回新的文件位置,执行错误时,返回-1,并且将errno设置为适当值。

    1. //将文件fd的位置设置为1825
    2. ret = lseek(fd, (off_t)1825, SEEK_SET);
    3. if (ret == (off_t)-1)
    4. //将文件的位置设置为文件的末端
    5. ret = lseek(fd, 0, SEEK_END);
    6. //找到文件当前的位置
    7. ret = lseek(fd, 0, SEEK_CUR);

    pread()和pwrite()函数

    1. #define _XOPEN_SOURCE 500
    2. #include
    3. ssize_t pread(int fd, void* buf, size_t count, off_t pos);
    4. 此调用会从文件fd的pos位置读取count字节放入到buf中
    5. ssize_t pwrite(int fd, const void*buf, size_t count, off_t pos);
    6. 将count字节从buf中写入到fd的文件pos位置
    7. 以上两个调用不会改变文件的位置

    截短文件ftruncate(int fd, off_t len)和truncate(const char* path, off_t len);

    1. #include
    2. #include
    3. int ftruncate(int fd, off_t len);
    4. int truncate(const char* path, off_t len);

     这两个系统调用会将指定的文件截短成len所指定的长度,不改变文件当前位置。

     select()  

    1. #include
    2. #include
    3. #include
    4. #include
    5. #define TIMEOUT 5 //select的等待时间,秒为单位
    6. #define BUF_LEN 1024 //读取缓冲区,字节为单位
    7. //编译:    gcc -o select_test select_test.cpp
    8. int main(void) {
    9. struct timeval tv;
    10. fd_set readfds;
    11. int ret;
    12. // 等候stdin的输入数据
    13. FD_ZERO(&readfds);
    14. FD_SET(STDIN_FILENO, &readfds);
    15. // 等候5秒的时间
    16. tv.tv_sec = TIMEOUT;
    17. tv.tv_usec = 0;
    18. ret = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
    19. if (ret == -1) {
    20. perror("select");
    21. return 1;
    22. } else if(!ret) {
    23. printf("%d seconds elapsed.\n", TIMEOUT);
    24. return 0;
    25. }
    26. // 是否可读
    27. if (FD_ISSET(STDIN_FILENO, &readfds)) {
    28. char buf[BUF_LEN+1];
    29. int len;
    30. // 保证不会遭到阻挡
    31. len = read(STDIN_FILENO, buf, BUF_LEN);
    32. if (len == -1) {
    33. perror("read");
    34. return 1;
    35. }
    36. if (len) {
    37. buf[len] = '\0';
    38. printf("read: %s\n", buf);
    39. }
    40. return 0;
    41. }
    42. fprintf(stderr, "This should not happen!\n");
    43. return 1;
    44. }

    poll()函数

    1. #include
    2. #include
    3. #include
    4. #define TIMEOUT 5 //poll的等待时间
    5. /*
    6. 使用poll()同时检查由读取stdin以及写入stdout是否会受到阻挡
    7. */
    8. int main() {
    9. struct pollfd fds[2];
    10. int ret;
    11. // 查看stdin输入
    12. fds[0].fd = STDIN_FILENO;
    13. fds[0].events = POLLIN;
    14. // 查看stdout是否可供写入
    15. fds[1].fd = STDOUT_FILENO;
    16. fds[1].events = POLLOUT;
    17. ret = poll(fds, 2, TIMEOUT*1000);
    18. if (ret == -1) {
    19. perror("poll");
    20. return 1;
    21. }
    22. if (!ret) {
    23. printf("%d seconds elapsed.\n", TIMEOUT);
    24. return 0;
    25. }
    26. if (fds[0].revents & POLLIN) {
    27. printf("stdin is readable\n");
    28. }
    29. if (fds[1].revents & POLLOUT) {
    30. printf("stdout is writable\n");
    31. }
    32. return 0;
    33. }

    运行上述程序

    ./poll

    输出stdout is writable

    添加一个输入,运行

    ./poll < xxxx.txt

    stdin is readable

    stdout is writable

    fdopen()将一个已打开的文件描述符fd转成流

    1. #include
    2. FILE * fdopen(int fd, const char* mode);

    关闭流

    fclose()关闭流

    1. #include
    2. int fclose(FILE* stream);

    关闭所有流

    1. #define _GNU_SOURCE
    2. #include
    3. int fcloseall(void);

    一次读取一个字符

    1. #include
    2. //返回类型需是int类型
    3. int fgetc(FILE* stream);

    将字符放回

    1. #include
    2. int ungetc(int c, FILE* stream);

    读取一整行

    1. #include
    2. char* fgets(char* str, int size, FILE* stream);
    1. char* s;
    2. int c;
    3. s = str;
    4. while(--n>0 && (c = fgetc(stream)) != EOF) {
    5. *s++ = c;
    6. }
    7. *s = '\0';

    遇到d时停止读取

    1. char* s;
    2. int c = 0;
    3. s = str;
    4. while(--n>0 && (c = fgetc(stream)) != EOF && (*s++ = c) != d);
    5. if (c == d)
    6. *--s = '\0';
    7. else
    8. *s = '\0';

    读取二进制数据

    1. #include
    2. size_t fread(void* buf, size_t size, size_t nr, FILE* stream);

    写入一个字符

    1. #include
    2. int fputc(int c, FILE* stream);

    写入一个字符串

    1. #include
    2. int fputs(const char* str, FILE* stream)

    fputs()会把str所指向的以null分割的字符串全部写入到stream流中,执行成功返回一个非负值,执行失败,返回EOF。

    写入二进制数据

    1. #include
    2. size_t fwrite(void* buf, size_t size, size_t nr, FILE* stream);
    3. 执行成功返回写入的元素数目,而不是字节数,执行失败,返回一个小于nr的值,指发生了错误。

     

    1. #include
    2. int main() {
    3. FILE* in, *out;
    4. struct pirate {
    5. char name[100]; //姓名
    6. unsigned long booty;
    7. unsigned int beard_len;
    8. } p, blackbeard = {"Edward Teach", 950, 48};
    9. // 将blackbear写入一个流中,再读出来
    10. out = fopen("data", "w");
    11. if (!out) {
    12. perror("fopen");
    13. return 1;
    14. }
    15. if (!fwrite(&blackbeard, sizeof(struct pirate), 1, out)) {
    16. perror("fwrite");
    17. return 1;
    18. }
    19. if (fclose(out)) {
    20. perror("fclose");
    21. return 1;
    22. }
    23. in = fopen("data", "r");
    24. if (!in) {
    25. perror("fopen");
    26. return 1;
    27. }
    28. if (!fread(&p, sizeof(struct pirate), 1, in)) {
    29. perror("fread");
    30. return 1;
    31. }
    32. if (fclose(in)) {
    33. perror("fclose");
    34. return 1;
    35. }
    36. printf("name=\"%s\" booty=%lu beard_len = %u\n", p.name, p.booty, p.beard_len);
    37. return 0;
    38. }

    查找流fseek()

    1. #include
    2. int fseek(FILE* stream, long offset, int whence);

     如果whence的值被设置为SEEK_SET,则文件位置会被设置为offset,如果whence的值被设置为SEEK_CUR,则文件位置会被设置为当前位置加上offset,如果whence的值被设置为SEEK_END,则文件的位置会被设置为文件末端加上offset。

    执行成功时返回0,清除EOF的指示器并取消ungetc()所造成的影响(如果有的话),发生错误返回-1,并将errno设置为适当值,

     fsetpos()

    1. #include
    2. int fsetpos(FILE* stream, fpos_t *pos);

    将流重新设置为开头

    1. #include
    2. void rewind(FILE* stream);
    3. //调用如下
    4. rewind(stream)
    5. 和下面的功能相同
    6. fseek(stream,0, SEEK_SET);

    注意:rewind没有返回值,因此无法传达错误信息,如果要确认错误信息,需要调用之前先清除errno的值,在事后检查。

    1. errno = 0;
    2. rewind(stream);
    3. if (errno)
    4. //错误

    获取当前位置

    lseek()函数调用结束会返回当前位置,fseek()函数不会,要获得当前位置使用ftell()函数

    1. #include
    2. long ftell(TILE* stream);

    发生错误返回-1,并且将errno设置为合适的值。

    fgetpos()

    1. #include
    2. int fgetpos(FILE* stream, fpos_t *pos);

    成功返回0,并且将位置保存在pos中。

     刷新一个流

    1. #include
    2. int fflush(FILE* stream);

    将流中的数据刷新至内核,如果stream为NULL,则进程中所有的流都会被刷新。

     检查错误ferror()

    1. #include
    2. int ferror(FILE* stream);

     用于检查流上是否有错误。

    feof()用于检测stream上是否设置了EOF指示器。

    1. #include
    2. int feof(FILE* stream);

     clearerr()用于清除stream之上的错误和EOF指示器。

    1. #include
    2. void clearerr(FILE* stream);

    获得相应的文件描述符

    1. #include
    2. int fileno(FILE* stream);

    设置缓冲模式
     

    1. #include
    2. int setvbuf(FILE* stream, char* buf, int mod, size_t size);

    setvbuf()函数会将stream的缓冲区设置为mode类型,_IONBF:未经缓冲,_IOLBF:行缓冲,_IOFBF:经块缓冲。_IONBF(在此情况下会忽略buf和size)除外,buf会指向一个大小为size字节的缓冲区,而标准IO将以此为特定流的缓冲区,如果buf的值为NULL,则glibc会自动分配一个缓冲区。

    打开流之后,必须setvbuf函数,而且必须在对流执行任何操作之前进行.

  • 相关阅读:
    yolov5 优化系列(三):修改损失函数
    标签属性 rel=“noopener noreferrer“ 原来这么有用
    企业日常公关如何抵御负面信息的入侵?
    什么是分布式锁?几种分布式锁分别是怎么实现的?
    CVE-2022-22978 Spring-security 认证绕过漏洞分析和漏洞挖掘思考
    OSIRISV4.1使用教程(最新可用版)
    Worthington果胶酶的特性及测定方案
    kettle应用-数据库表插入/更新
    牛客竞赛每日俩题 - Day6
    03 矩阵与线性变换
  • 原文地址:https://blog.csdn.net/wj617906617/article/details/133321553