最全的Linux教程,Linux从入门到精通
======================
-
linux从入门到精通(第2版)
-
Linux系统移植
-
Linux驱动开发入门与实战
-
LINUX 系统移植 第2版
-
Linux开源网络全栈详解 从DPDK到OpenFlow
第一份《Linux从入门到精通》466页
====================
内容简介
====
本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。
本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。
需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
🌈解疑答惑
同样的一个程序,向显示器打印输出4行文本,向普通文件(磁盘上)打印的时候,变成了7行,说明上面测试,并不影响系统接口
- C的IO接口是打印了2次的
- 系统接口,只打印了一次
我们最后调用fork,上面的函数已经被执行完了,但不代表数据已经被刷新了
🥑缓冲区是谁提供的
🔥曾经“我们所谈的缓冲区”,绝对不是由OS提供的,如果是OS同一提供,那么我们上面的代码,表现应该是一样的,而不是C的IO接口打印两次,所以是C标准库提供并且维护的用户级缓冲区
fputs
把不是直接把数据直接放进操作系统,而是加载进C标准库的缓冲区中,加载完后自己可以直接返回;如果直接调用的是write接口,则是直接写给OS,不经过缓冲区
- C语言提供的接口都是向显示器打印的,刷新策略都是行刷新,那么最后执行fork的时候 —— 一定是函数执行完了 && 数据已经被刷新了(因为都带
\n
),所以fork执行无意义 - 如你对应的程序进行了重定向 ——> 要向磁盘文件打印 ——> 隐形的刷新策略变成了全缓冲!—— >
\n
便没有意义了 ——> 函数一定执行完了,数据还没有刷新!! 在当前进程对应的C标准库中的缓冲区中!!
这缓冲区的部分数据是父进程的数据吗? 是的
fork
之后,父子分流,父进程的数据发生写时拷贝给子进程,所以C标准库会打印两次
总结:
- 重定向到文件导致:刷新策略改变(变成全缓冲)
- 写时拷贝:父子进程各自刷新一次
🥑用户级缓冲区在哪里?
当我们用fflush
强制刷新的时候
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
//C语言提供的
printf("hello printf\n");
fprintf(stdout, "hello fprintf\n");
const char \*s = "hello fputs\n";
fputs(s, stdout);
//OS提供的
const char \*ss = "hello write\n";
write(1, ss, strlen(ss));
//fork之前,强制刷新
fflush(stdout);
//最后调用fork的时候,上面的函数已经被执行完了
fork();//创建子进程
return 0;
}
结果如下:
数据在fork之前,已经被fflush刷新了,缓冲区里没有数据了,也就不存在写时拷贝。
这里更夸张的是,fflush(stdout)
只告诉了stdout就能知道缓冲区在哪里?
FILE \*fopen(const char \*path, const char \*mode);
- C语言中,open打开文件,返回的是
FILE *
,struct FILE结构体 — 内部封装了fd,还包含了该文件fd对应的语言层的缓冲区结构!(远在天边,近在眼前)
我们可以看看FILE结构体:
//在/usr/include/libio.h
struct \_IO\_FILE {
int _flags; /\* High-order word is \_IO\_MAGIC; rest is flags. \*/
#define \_IO\_file\_flags \_flags
//缓冲区相关
/\* The following pointers correspond to the C++ streambuf protocol. \*/
/\* Note: Tk uses the \_IO\_read\_ptr and \_IO\_read\_end fields directly. \*/
char\* _IO_read_ptr; /\* Current read pointer \*/
char\* _IO_read_end; /\* End of get area. \*/
char\* _IO_read_base; /\* Start of putback+get area. \*/
char\* _IO_write_base; /\* Start of put area. \*/
char\* _IO_write_ptr; /\* Current put pointer. \*/
char\* _IO_write_end; /\* End of put area. \*/
char\* _IO_buf_base; /\* Start of reserve area. \*/
char\* _IO_buf_end; /\* End of reserve area. \*/
/\* The following fields are used to support backing up and undo. \*/
char \*_IO_save_base; /\* Pointer to start of non-current get area. \*/
char \*_IO_backup_base; /\* Pointer to first valid character of backup area \*/
char \*_IO_save_end; /\* Pointer to end of non-current get area. \*/
struct \_IO\_marker \*_markers;
struct \_IO\_FILE \*_chain;
int _fileno; //封装的文件描述符
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /\* This used to be \_offset but it's too small. \*/
#define \_\_HAVE\_COLUMN /\* temporary \*/
/\* 1+column number of pbase(); 0 is unknown. \*/
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/\* char\* \_save\_gptr; char\* \_save\_egptr; \*/
_IO_lock_t \*_lock;
#ifdef \_IO\_USE\_OLD\_IO\_FILE
};
所以在C语言上,进行写入的时候放进缓冲区,定期刷新
C语言打开的FILE是文件流。C++中的cout 是类;里面必定包含了 fd、buffer(缓冲区)
🌏设计用户层缓冲区的代码 ~ 实战
💢struct file
的设计
struct MyFILE\_{
int fd; //文件描述符
char buffer[1024]; //缓冲区
int end; //当前缓冲区的结尾
};
💢主函数
open文件 —— fputs输入 —— fclose关闭,接口函数都要我们逐一实现
int main()
{
MyFILE \*fp = fopen\_("./log.txt", "r");
if(fp = NULL)
{
printf("open file error");
return 0;
}
fputs\_("hello world error", fp);
fclose\_(fp);
}
我们发现:C语言的接口一旦打开成功,全部都要带上FILE*
结构,原因很简单,因为什么数据都在这个FILE结构体中
FILE \*fopen(const char \*path, const char \*mode);
//以下全是要带FILE\*
int fputc(int c, FILE \*stream);
int fclose(FILE \*fp);
size_t fread(void \*ptr, size_t size, size_t nmemb, FILE \*stream);
💢接口实现
💦fputs
//此处刷新策略还没定 全部放进缓冲区
void fputs\_(const char \*message, MyFILE \*fp)
{
assert(message);
assert(fp);
strcpy(fp->buffer + fp->end, message);//abcde\0
fp->end += strlen(message);
}
运行结果:
上面覆盖了\0
,strcpy会在结尾时候自动添加\0
若要往显示器上打印:变成行刷新
if(fp->fd == 0)
{
//标准输入
}
else if(fp->fd == 1)
{
//标准输出
if(fp->buffer[fp->end-1] =='\n' )
{
//fprintf(stderr, "fflush: %s", fp->buffer); //2
write(fp->fd, fp->buffer, fp->end);
fp->end = 0;
}
}
else if(fp->fd == 2)
{
//标准错误
}
else
{
//其他文件
}
}
测试用例:
fputs\_("one:hello world error", fp);
fputs\_("two:hello world error\n", fp);
fputs\_("three:hello world error", fp);
fputs\_("four:hello world error\n", fp);
结果:当遇到\n,才刷新
💦fflush刷新
当end!=0 ,就刷新进内核
内核刷新进外设,这就要用一个函数syncfs
#include <unistd.h>
//将缓冲区缓存提交到磁盘
int syncfs(int fd);
具体实现:
void fflush(MyFILE \*fp)
{
assert(fp);
if(fp->end != 0)
{
//暂且认为刷新了 ——其实是把数据写到 内核
write(fp->fd, fp->buffer, fp->end);
syncfs(fp->fd); //将数据写入到磁盘
fp->end = 0;
}
}
💦fclose
关闭之前要先刷新
void fclose(MyFILE \*fp)
{
assert(fp);
fflush(fp);
close(fp->fd);
free(fp);
}
💢附源码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#define NUM 1024
struct MyFILE\_{
int fd; //文件描述符
char buffer[1024]; // 缓冲区
int end; //当前缓冲区的结尾
};
typedef struct MyFILE\_ MyFILE;//类型重命名
MyFILE \*fopen\_(const char \*pathname, const char \*mode)
{
assert(pathname);
assert(mode);
MyFILE \*fp = NULL;//什么也没做,最后返回NULL
if(strcmp(mode, "r") == 0)
{
}
else if(strcmp(mode, "r+") == 0)
{
}
**先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里**
**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/ebfcdb2ae8c5e16f7ffb4140c66b36b2.png)
![img](https://img-blog.csdnimg.cn/img_convert/1d78427b960eec1f4436410e8100940c.png)
![img](https://img-blog.csdnimg.cn/img_convert/9a16ef0198d59eda46d497b7397882ee.png)
![img](https://img-blog.csdnimg.cn/img_convert/22ef58abad055b18828434aca514aa76.png)
![img](https://img-blog.csdnimg.cn/img_convert/face67bde27de92b037a138ea3388dbf.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
能够帮助到想自学提升又不知道该从何学起的朋友。**
[外链图片转存中...(img-EclyQAVJ-1714971508161)]
[外链图片转存中...(img-MM1c67Xp-1714971508162)]
[外链图片转存中...(img-vrUN5OD4-1714971508162)]
[外链图片转存中...(img-kPODailt-1714971508162)]
[外链图片转存中...(img-FYa9hPsn-1714971508162)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**