@TOC
1.vscode的下载
这里放一篇大佬超详细解析的博客,包括解决下载速度慢的问题 vscode下载博客
2. vscode的使用
1. 连接远端
vscode是一个编辑器 winodows +linux 联合开发 ,用vscode取代vim 将本地将vscode打造开发环境 -- vscode的本地环境搭建
红框中填入 linux主机名字
输入 ssh 用户名+ 主机名 将ssh 用户名和IP地址 更新到 本地的哪一个配置文件中
再次重启vscode,在SSH箭头下就有了IP地址存在
IP地址处 按右键,在新窗口连接 即新创建一个终端
选择Linux平台 然后在白框中输入用户名 对应的密码
在新创建的终端上,点击电脑图标,SSH出现绿色的对号即表示连接成功
2. 在vscode创建文件并运行程序
打开文件夹即可打开在Linux下自己用户的家目录
需要注意的是当打开文件后,还需再次输入密码
创建一个新文件,并命名为test.c ,此时出现一个黑点,说明本地代码并没有同步给远端
在xshell上,打开对应新创建的test.c 什么都都没有
输入 CTRL S 后,黑点就消失了,对应就保留到远端中了
切换到命令行
输入 CTRL ~ 即可 打出在Linux内部内置的命令行
可以在vscode上运行可执行程序
3. 安装常见插件
一定是要先连接IP地址,否则直接下载就会下到本地
C/C++
C/C++Extension Pack——c/c++扩展包
c/c++Themes 在vscode上设置主题
Chinese 将英文转换为简体中文
vscode-icons 改变编辑器里面的文件图标
filesize 左下角显示源文件大小的插件
Include AutoComplete 自动头文件包含
GBKtoUTF8 自动将GBK转换为UTF8
3. 进程间通信
管道的进程具有独立性的一个进程挂掉,不影响另一个进程, 可会增加通信的成本
要让两个不同的进程进行通信,前提条件是:先让两个进程看到同一份 资源在操作系统内创建一份公共的资源,既不属于进程A,又不属于进程B,进程A能看到资源,进程B也能看到资源 把进程A生产的数据放入 资源中 ,进程B就可以拿到数据放入自己的上下文中
1. 简单举例
who
查看当前用户哪一个处于登录状态
wc
统计文本行有多少行的命令who | wc -l
统计当前正在登录用户的个数
who进程 以写方式打开文件wc -l 进程 以读方式 打开文件 who进程将自己的标准输出重定向到管道中 wc -l 进程将自己的标准输入重定向到管道中
2.管道原理
每一个进程被创建时都有自己的文件描述符表
1. 新创建的文件被打开时,有自己的缓冲区,它是由操作系统提供的纯纯的内存文件,不需要将自己的内容刷新到磁盘中 , 以读方式和写方式分别打开同一个文件
2. 当前进程进行一次fork操作系统会为子进程创建PCB结构,操作系统也会把文件描述符表拷贝给子进程 父进程打开的文件内容不需要再次拷贝给子进程 因为是创建子进程,是需要把进程相关的内核数据结构拷贝就可以了,右侧属于文件系统,属于操作系统在内存中打开的文件
文件描述表中保存的是文件的地址,所以依旧会指向父进程所对应的文件
管道只支持单向通信 确定数据流向,关闭关闭不需要的fd 若想要子进程进行写入,父进程进行读取,关闭子进程对应的读端,以及父进程的写端 此时就可以正常通信了
为什么把读写都打开,只打开读或者写不可以吗?
若只打开读方式打开,则被子进程继承下去后依旧是只能以读方式打开,无法进行数据交互的
3. 通过父子进程理解管道
在vscode中 点击新建文件夹,即可创建目录 pipe
在目录pipe上 点击右键 新建文件 ,即可 生成 pipe.cc(cc结尾代表cpp) 的文件
1. 创建匿名管道
pipe 作用是 创建一个无名管道pipe函数 参数是两个元素的数组参数作为输出型参数
要一次获得该管道文件的读和写,对应的是两个文件描述符,需要将两个文件描述符的数字返回
pipe的参数是一个数组,实际上传入的是数组首元素的地址若返回值小于0,则通过errno(出错码)来得到出错结果strerror 将错误码转换成错误码描述的
最终发现打印出来的结果 为 3 与 4 ,正好对应 数组中下标 3与4的位置
系统调用为什么可以使用c语言的errno
正常来说,是调用c语言接口出错了,才调用的errno 或者 strerror的为什么调用系统调用接口时,也会使用 errno来说明错误的原因系统调用接口是由系统使用c语言的一套软件
2.创建子进程以及通信
一般认为pipefd[0] 为读端 , pipefd[1]为写端用close来关闭文件描述符所以关闭子进程的读端 ,关闭父进程的写端 将子进程变化的数据导给父进程
把namestr 字符串内容与 计数器 cnt 以及pid值 构建成一个字符串 打包给 父进程
使用snprintf函数 将amestr 字符串内容与 计数器 cnt 以及pid值写入buffer中,并规定传入buffer大小c_str():返回const char*类型的指针
ssize_t write(int fd, const void *buf, size_t count);fd代表文件描述符buf代表 缓冲区 count代表 缓冲区大小 使用write 将缓冲区的count大小的数据写入 fd中
将buffer中的所有数据都传入读端中
3. 父进程读取消息
使用write 将缓冲区的count大小的数据写入 fd中ssize_t read(int fd, void *buf, size_t count);从文件描述符fd中将我们想要的数据,按照数据块的方式读取出来
返回值代表多少字节,读取到文件结尾为0,失败为-1read读取时并不会把buffer当作一个字符串,而我们要把buffer看作是一个字符串,所以要预留出\0的位置即 sizeof(buffer)-1 将读端读取到buffer字符串的内容
4. 完整代码
#include<iostream>
#include<cerrno>//C++提供
#include<unistd.h>
#include<string.h>
#include<cassert>
#include<string>
#include<cstdio>
#include<stdlib.h>
using namespace std;
int main()
{
int pipefd[2]={0};
//1.创建管道
int n=pipe(pipefd);
//返回值为0 则成功
if(n<0)//说明出错
{
cout<<"pipe error,"<<errno<<": "<<strerror(errno)<<endl;
return 1;
}
//返回0和1里面的文件描述符
cout<<"pipefd[0]: "<<pipefd[0]<<endl;
cout<<"pipefd[1]: "<<pipefd[1]<<endl;
//2.创建子进程
pid_t id=fork();
assert(id!=-1);//返回-1,说明创建子进程失败
if(id==0)
{
//子进程
//让父进程进行读取,让子进程进行写入
close(pipefd[0]);//关闭子进程的读端
//开始通信
const string namestr="hello,我是子进程";
int cnt=1;
char buffer[1024];
while(true)
{
snprintf(buffer,sizeof(buffer),"%s:计数器,PID:%d\n",namestr.c_str(),cnt++,getpid());
write(pipefd[1],buffer,strlen(buffer));
}
close(pipefd[1]);//当子进程用完,就关闭
exit(0);//退出
}
//父进程
//关闭不需要的fd (文件描述符)
close(pipefd[1]);//关闭父进程的写端
//4.开始通信
char buffer[1024];
while(true)
{
int n=read(pipefd[0],buffer,sizeof(buffer)-1);
if(n>0)//读取成功
{
buffer[n]='\0';
//由子进程传过来的消息
cout<<"我是父进程:child send give message:"<<buffer<<endl;
}
}
close(pipefd[0]);//关闭父进程的读端
return 0;
}
4. 管道特点
1.单向通信2.管道本质是文件,因为fd的声明周期随进程,管道的生命周期随进程的3.管道通信 ,通常用来进行具有血缘关系的进程,来进行进程通信的,常用于父子通信 pipe打开管道,并不清楚管道的名字,被称为匿名管道 4.管道面向字节流(对写入和读取的次数无关) 5.具有一定的协同能力,让读端和写端能够按照一定的步骤进行通信 (若写端写满了,就需要等待读端读好才能继续写 当读端把管道的数据读完后,如果写端不发数据,读端只能等待)
5. 场景
1. 如果我们read读取完毕了所有的管道数据,如果对方不发,就只能等待2. 如果写端将管道写满了,就不能再写了3.若关闭写端,读取完毕管道数据,再读,就会read返回0,表明读到了文件结尾 4.写端一直写,读端关闭,没有意义操作系统不会维护无意义,低效率,或者浪费资源的事情,操作系统会通过信号来终止进程(13 SIGPIPE)