进程间通信IPC(一)(半双工管道和消息队列)

引言:
之前学习的进程之间交换信息的方法只能由fork或exec传送打开文件,或者文件系统。但是这种通讯方式有局限性,接下来将说明进程之间相互通信的其他技术——IPC(InterProcessCommunication),过去UNIX系统IPC是各种进程间通信方式的统称,但是,其中极少能在所有UNIX系统中实现移植。随着POSIX和Open Group(以前是X/Open)标准化的推进和影响扩大,情况随已得到改善,但是差别仍然存在。以下将介绍几种实现所支持的不同形式的IPC。

单机版进程间通信方式:

  • 半双工管道(包括无名管道和命名管道)

  • 消息队列

  • 信号量

  • 共享内存

多机版进程间通讯方式:

  • 套接字(socket)
  • streams

管道(父进程创建):

概念:
管道,通常指无名管道,是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”,本质:内核缓冲区。

特点:

  • 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端,当数据从管道中读取后管道中就没有了。
  • 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
  • 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。本质:内核缓冲区.

在这里插入图片描述
如何建立半双工管道:

管道是由调用pipe函数来创建

#include <unistd.h>
int pipe(int pipefd[2]);函数的参数是:含有两个元素的整型数组
返回值:返回:成功返回0,出错返回-1 
fd参数返回两个文件描述符,fd[0]指向管道的读端read(fd[0],-,-)
其中read()函数如果读不到东西,会阻塞。
fd[1]指向管道的写端,write(fd[1],-,-)。向管道文件读写数据其实
是在读写内核缓冲区。要关闭管道只需要将读端和写端close掉即可。fd[1]的写出是fd[0]的读入。0对应标准输入,1对应标准输出一样。
默认标准输入对应的设备是键盘,标准输出和标准错误对应的是显示器
linux下一起皆文件,设备一定是文件,文件不一定是设备,标准输入
和标准输出就不是文件,他们是链接文件,什么是链接文件?文件内容
是另一个文件的地址的文件称为链接文件。

标准输入、标准输出解释

父进程给子进程信息:

#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<string.h>
#include<stdlib.h>
int main()
{int fd[2];int status;pid_t fpid;char* writebuf=NULL;writebuf=(char*)malloc(1024);printf("请输入父进程要传递给子进程的消息:\n");scanf("%[^\n]",writebuf);if(pipe(fd)==-1){printf("creat file fail\n");}fpid=fork();if(fpid<0){printf("创建子进程失败\n");perror("fork");}else if(fpid>0){close(fd[0]);write(fd[1],writebuf,strlen(writebuf));waitpid(fpid,&status,0);if(WIFEXITED(status)){printf("子进程正常结束,状态值是:%d\n",WEXITSTATUS(status));}close(fd[1]);}else{close(fd[1]);char* readbuf=NULL;int n_read;readbuf=(char*)malloc(strlen(writebuf));n_read=read(fd[0],readbuf,strlen(writebuf));printf("子进程得到数据:%s,字节数是:%d\n",readbuf,n_read);close(fd[0]);}return 0;
}这个程序:起初当输入字符串中间有空格时,子进程只会收到空格之前的字符串
问题诊断:scanf()遇到空格、回车、Tab则认为输入结束,后面的就不会当做输入了
解决方法:%s换为%[^\n](^有非的意思,即不遇到\n不停止)或者用gets()scanf输入字符串的时候不会接收Space空格,回车Enter,Tab键,则认为输入结束。
scanf函数直接从输入缓冲区中取数据,而并非从键盘(也就是终端)缓冲区读取。1、空格:空格键产生的字符,ascii码十进制:32
2、空字符:字符串结束标志‘\0’,为被动添加,ascii码十进制:0
3、字符0:ascii码十进制:48

子进程发送消息给父进程:

#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<string.h>
#include<stdlib.h>
int main()
{int fd[2];int status;pid_t fpid;char* writebuf=NULL;writebuf=(char*)malloc(1024);printf("请输入父进程要传递给子进程的消息:\n");scanf("%[^\n]",writebuf);if(pipe(fd)==-1){printf("creat file fail\n");}fpid=fork();if(fpid<0){printf("创建子进程失败\n");perror("fork");}else if(fpid>0){sleep(1);close(fd[1]);char* readbuf=NULL;int n_read;readbuf=(char*)malloc(strlen(writebuf));n_read=read(fd[0],readbuf,strlen(writebuf));waitpid(fpid,&status,0);printf("父进程得到数据:%s,字节数是:%d\n",readbuf,n_read);if(WIFEXITED(status)){printf("子进程正常结束,状态值是:%d\n",WEXITSTATUS(status));}}else{close(fd[0]);write(fd[1],writebuf,strlen(writebuf));}return 0;
}

memcpy()函数介绍、scanf输入字符串遇到空格?

FIEO(有名管道,半双工):

无名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了命名管道(FIFO),也叫有名管道、FIFO 文件。命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。

命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于:

  • FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中,FIFO文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。各进程可以打开这个文件进行read/write,实际上是在读写内核通道,这样就实现了进程间通信。
  • 当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。
  • FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。
  • 另外,使用统一fifo文件,可以有多个读端和多个写端。

创建有名管道:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);pathname: 普通的路径名(就是创建的管道的位置),也就是创建后 FIFO 的名字。
mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同返回值:成功:0失败:如果文件已经存在,则会出错且返回 -1。如果因为文件存在引起的错误,则会返回-1并将errno的值赋EEXIST可以用下面的代码找出其他的出错原因
if(mkfifo("./fifodir",0666)==-1&&errno!=EEXIST){printf("管道创建失败\n");perror("because");
}

注意:
当进程对命名管道的使用结束后,命名管道依然存在于文件系统中,除非对其进行删除操作。命名管道的数据读取后也会消失(不能反复读取),即且严格遵循先进先出的规则。因此,每次命名管道文件使用完后,其大小为0字节,不会产生中间临时文件。

命名管道的默认操作:

  • 后期的操作,把这个命名管道当做普通文件一样进行操作:open()、write()、read()、close()。但是,和无名管道一样,操作命名管道肯定要考虑默认情况下其阻塞特性。
  • 下面验证的是默认情况下的特点,即 open() 的时候没有指定非阻塞标志( O_NONBLOCK )。open() 以只读方式打开FIFO 时,要阻塞到某个进程为写而打开此 FIFO。open() 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO。
  • 简单一句话,只读等着只写,只写等着只读,只有两个都执行到,才会往下执行。
  • 在这里我们需要注意一点,就是不能以 O_RDWR 方式打开管道文件,这种行为是未定义的。倘若有一个进程以读写方式打开了某个管道,那么该进程写入的数据又会被该进程本身读取,而管道一般只用于进程间的单向数据通信。

管道打开方式:

  • (1)只读且阻塞方式
    open(const char *pathname, O_RDONLY);
  • (2)只读且非阻塞方式
    open(const char *pathname, O_RDONLY | O_NONBLOCK);
  • (3)只写且阻塞方式
    open(const char *pathname, O_WRONLY);
  • (4)只写且非阻塞方式
    open(const char *pathname, O_WRONLY | O_NONBLOCK);

读端代码:

#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<errno.h>
#include<string.h>
int main()
{char readbuf[30];int n_read;int fd;memset(readbuf,'\0',30);if(mkfifo("./fifodir",0600)==-1&&errno!=EEXIST){printf("mkfifo fail\n");perror("mkfifo");}fd=open("./fifodir",O_RDONLY);while(1){n_read=read(fd,readbuf,30);printf("读取到%d个字节,内容是%s\n",(int)strlen(readbuf),readbuf);}close(fd);return 0;
}

写端代码:

include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<errno.h>int main()
{int fd;fd=open("./fifodir",O_WRONLY);while(1){write(fd,"hello reader",20);sleep(1);}close(fd);return 0;
}

消息队列、消息队列参数详解

什么是消息队列?

  • 消息队列是消息的链表,存放在内核中并由消息队列标识符表示。
  • 消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型。
  • 但是同管道类似,它有一个不足就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数(MSGMNB),系统上消息队列的总数上限(MSGMNI)。可以用cat /proc/sys/kernel/msgmax查看具体的数据。

特点:

  • 消息队列是面向记录的,其中的消息具有特定的格式以及优先级
  • 消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除(生命周期随内核,消息队列会一直存在,需要我们显示的调用接口删除或使用命令删除)。
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
  • 克服了管道只能承载无格式字节流的缺点
  • 消息队列可以双向通信

对于消息队列,要知道如何创建一个消息队列,如何将消息添加到消息队列,如何从消息队列读取信息

ftok()函数:

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。调用成功返回一个key值,用于创建消息队列,如果失败,返回-1键值和消息队列标识符的关系:
在创建一个消息队列(其他ipc相同)时,需要先通过文件路径名和项目ID获取一个键值,
然后通过此
键值由内核生成标识符,在以后可通过此标识符来使用此消息队列。

查询文件索引节点号的方法是:

ls  -i
ls -al//显示所有文件的所以值,包括隐藏文件
执行结果:
fhn@ubuntu:~/jincheng/communication$ ls -i
932272 fifo     932283 msgread    932262 msgsend.c     932274 read    932250 write.c
932256 fifo.c   932263 msgread.c  932265 nomamepipe    932279 read.c  932267 znomamepipe
932229 fifodir  932280 msgsend    932236 nomamepipe.c  932275 write   932248 znomamepipe.c

msgget函数:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);功能:创建和访问一个消息队列 
key:某个消息队列的名字,用ftok()产生
msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,
如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,
如果存在则出错返回。如果将key值设为IPC_PRIVATE则创建私有的消息队列,只能有一个进程访问。
msgflag由九个权限标志构成,0644,它们的用法和创建文件时使用的mode模式标志是一样的(但是消息队列没有x(执行)权限)返回值:成功返回一个非负整数,即消息队列的标识码,失败返回-1

为什么要有键值和标识符两个值呢?
标识符是对于用户操作而言的,让用户感觉操作和对文件的操作相同,键是对于系统内部说的。
我们使用ftok来创建键值,具体你可以man一下fotk函数,大概是这样的:按给定的路径名取得其stat结构,从该结构中取出部分st_dev和st_ino字段,然后再与项目id组合起来,如果两个路径名引用两个不同的文件,那么,对这两个路径名调用ftok通常返回不同的键,但是,因为i节点号和键通常都存放在长整型中,于是创建键时可能会丢失信息,这意味着,如果使用同一项目id,那么对于不同文件的两个路径名可能产生相同的键。而标识符是唯一确定的,可以用来区别于其他ipc的。

msgsnd()函数:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);功能:把一条消息添加到消息队列中
参数:
msgid:由msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)
msgflg:默认为0
返回值:成功返回0,失败返回-1消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型struct msgbuf {long mtype;       /* message type, must be > 0 */char mtext[1];    /* message data */};消息队列内一个节点类型如下:
struct msq_Node    
{    Type msq_type;  //类型    Length msg_len; //长度    Data msg_data;  //数据    struct msg_Node *next;    
};  

msgrcv()函数:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgid:由msgget函数返回的消息队列标识码
msgp:指针指向准备接收的消息
msgze:msgp指向的要存消息内存的长度(不包括消息类型的long int长整型)
msgtyp:msgtyp==0返回队列中第一个消息msgtyp>0返回队列中消息类型为msgtyp的第一个消息msgtyp<0返回队列中消息类型小于或等于msgtyp绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出msgtyp值非0时用以非先进先出次序读消息,也可以把msgtyp看做优先级的权值。
msgflg:默认为0,阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
功能:是从一个消息队列接受消息
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

msgctl()函数:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);功能:消息队列的控制函数 第一个参数msgqid 是消息队列对象的标识符。
第二个参数是函数要对消息队列进行的操作,它可以是:
IPC_STAT:取出系统保存的消息队列的msqid_ds 数据,并将其存入参数buf 指向的msqid_ds 结构中。
IPC_SET:设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds结构给出。
IPC_RMID:将队列从系统内核中删除,此时第三个参数设为NULL。
这三个命令的功能都是明显的,所以就不多解释了。唯一需要强调的是在IPC_STAT命令中队列的msqid_ds 数据中唯一能被设定的只msg_perm 成员,其是ipc_perm 类型的数据。而ipc_perm 中能被修改的只有mode,pid 和uid 成员。其他的都是只能由系统来设定的。成功返回0,失败返回-1

消息队列需要手动删除IPC资源

linux下消息队列的查看与删除(ipcs&ipcrm的使用)

消息队列接收端:

#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
typedef struct msgbuf
{long mtye;char mtext[128];
}MSG,*PMSG;
int main()
{key_t key;int msgid;MSG readbuf;MSG sendbuf;sendbuf.mtye=666;strcpy(sendbuf.mtext,"hello sender,i have receive your msg");key=ftok(".",30);msgid=msgget(key,IPC_CREAT|0600);//flage使用IPC_CREAT表示若消息队列不存在则创建存在则打开后返回//0600是在没有消息队列时创建消息队列的权限,和文件那里那个权限一样if(msgid==-1){printf("make fail\n");perror("why");}memset(readbuf.mtext,'\0',128);msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),777,0);printf("msgrcv得到消息:%s\n",readbuf.mtext);msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);return 0;
}

消息队列发送端:

#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
typedef struct msgbuf
{long mtye;char mtext[128];
}MSG,*PMSG;
int main()
{key_t key;int msgid;MSG sendbuf;MSG readbuf;sendbuf.mtye=777;strcpy(sendbuf.mtext,"hello i am sender");key=ftok(".",30);msgid=msgget(key,IPC_CREAT|0600);//flage使用IPC_CREAT表示若消息队列不存在则创建存在则打开后返回//0600是在没有消息队列时创建消息队列的权限,和文件那里那个权限一样if(msgid==-1){printf("make fail\n");perror("why");}msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);printf("msgsnd发送消息完成:%s\n",sendbuf.mtext);msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),666,0);printf("msgsnd读到消息:%s\n",readbuf.mtext);msgctl(msgid,IPC_RMID,NULL);//等同于在命令行删除return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Seata相关概念

相关概念 XID&#xff1a;一个全局事务的唯一标识 Transaction Coordinator (TC)&#xff1a; 事务协调器&#xff0c;维护全局事务的运行状态&#xff0c;负责协调并驱动全局事务的提交或回滚&#xff08;可以理解为事务的协调者&#xff09;。 Transaction Manager (TM)&…

Program terminated with signal SIGSEGV, Segmentation fault.

问题&#xff1a; 在程序运行时出现了&#xff1a;Segmentation fault (core dumped)&#xff0c;分段故障(堆芯转储)也就是段错误。 我首先在一篇博客上面找到如何使用gdb调试&#xff1a; 1、首先使用ulimit -a查看你的core file size是否为0.如果不是的话就请跳到步骤3&am…

NFS简介

NFS 是Network File System的缩写&#xff0c;即网络文件系统。一种使用于分散式文件系统的协定&#xff0c;由Sun公司开发&#xff0c;于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据&#xff0c;让应用程序在客户端通过网络访问位于服…

Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理

Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理 本博文主要介绍 Laravel 框架中 Eloquent 对一对多关系的处理以及在 Laravel Administrator(后台扩展包)中的应用。 您的数据库可能是彼此相关的。比方&#xff0c;一篇博客文章可能有很多评论&#xff0c;或者一个订…

进程间通信IPC(二)(共享内存、信号、信号量)

共享内存&#xff1a; 共享内存就是允许两个或多个进程共享一定的存储区。就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候&#xff0c;其它进程都会察觉到这个更改。因为数据不需要在客户机和服务器端之间复制&am…

分布式理论CAP定理

CAP原则又称CAP定理&#xff0c;指的是在一个分布式系统中&#xff0c; Consistency&#xff08;一致性&#xff09;、 Availability&#xff08;可用性&#xff09;、Partition tolerance&#xff08;分区容错性&#xff09;&#xff0c;三者不可兼得。 998年&#xff0c;加州…

xmlWriter 以UTF-8格式写xml问题

dom4j中的XMLWriter提供以下几种构造方法&#xff1a; XMLWriter() XMLWriter(OutputFormat format) XMLWriter(OutputStream out) XMLWriter(OutputStream out, OutputFormat format) XMLWriter(Writer writer) XMLWriter(Writer writer, OutputFormat format) 最简单常…

linux线程(互斥锁、条件)

线程概念&#xff1a; 典型的UNIX/Linux进程可以看成只有一个控制线程&#xff1a;一个进程在同一时刻只做一件事情。有了多个控制线程后&#xff0c;在程序设计时可以把进程设计成在同一时刻做不止一件事&#xff0c;每个线程各自处理独立的任务。 进程是程序执行时的一个实例…

linux网络编程、socket编程

进程间通信&#xff1a; 特点&#xff1a;依赖于内核&#xff0c;造成缺陷——无法实现多机通信。 网络&#xff1a; 地址&#xff1a;由IP地址&#xff08;IP地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一个逻辑地址&#xf…

Linux文件和目录权限笔记

查看文件或者目录的权限命令&#xff1a;ls -al # -a 表示全部文件包含隐藏文件&#xff0c;-l 表示列出每个文件的详细信息比如执行 ls -altotal 115drwxr--x--- 4 root root 4096 Oct 24 02:07 install.log格式说明&#xff1a;通过 ls -al 格式化输出的文件详细信息&#x…

python基础:序列(列表、元组、字符串)、函数、字典、集合

Python语言运行环境&#xff1a; windowslinuxunixMacos等等 博客记录内容&#xff1a; Python3的所有语法、面向对象思维、运用模块进行编程、游戏编程、计算机仿真。 Python是什么类型的语言&#xff1a; Python是脚本语言&#xff0c;脚本语言(Scripting language)是电脑…

python基础(文件、异常、模块、类、对象)

文件&#xff1a; 打开文件使用open函数&#xff0c;open()的第一个参数是&#xff1a;要打开文件的路径&#xff0c;如果只传入文件名那么将在当前文件下查找文件并打开。第二个参数是&#xff1a;文件的打开模式&#xff0c;其他参数都是默认的。文件的打开模式如下图所示&a…

redis 和 memcached 的区别

redis 和 memcached 的区别 对于 redis 和 memcached 我总结了下面四点。现在公司一般都是用 redis 来实现缓存&#xff0c;而且 redis 自身也越来越强大了&#xff01; redis支持更丰富的数据类型&#xff08;支持更复杂的应用场景&#xff09;&#xff1a;Redis不仅仅支持简…

树莓派入门(树莓派登录的几种方式)

什么是嵌入式&#xff1f; 嵌入式即嵌入式系统&#xff0c;IEEE&#xff08;美国电气和电子工程师协会&#xff09;对其定义是用于控制、监视或者辅助操作机器和设备的装置&#xff0c;是一种专用的计算机系统。国内普遍认同的嵌入式系统定义是以应用为中心&#xff0c;以计算…

Linux库概念及相关编程(动态库、静态库、环境变量)

分文件编程&#xff1a; 好处&#xff1a;分模块编程思想&#xff0c;功能和责任划分清楚便与调试&#xff0c;main函数简洁&#xff0c;代码易于阅读。编程时头文件有的是使用<>这个符号括起来的&#xff0c;有的是" "使用的是双引号&#xff0c;使用尖括号括…

kali扫描内网ip_Metasploit路由转发实现内网渗透

利用背景在渗透的过程中常常会遇到这种场景&#xff1a;我们已经通过web渗透拿下一台内网服务器&#xff0c;为了进一步进行内网渗透&#xff0c;我们会利用“沦陷主机”作为跳板进行进一步的内网渗透&#xff0c;扩大战果。现在假设的场景是此时我们已经拿下一台内网服务器的远…

.NET Core 3.0 中的新变化

译者&#xff1a;楚人Leo译文&#xff1a;http://www.cnblogs.com/leolion/p/10585834.html原文&#xff1a;https://msdn.microsoft.com/en-us/magazine/mt848631.aspx.NET Core 3.0 是 .NET Core 平台的下一主要版本。本文回顾 .NET Core 发展历史&#xff0c;并展示了它是如…

树莓派GPIO口的使用(外设相关开发WringPi库的使用,超声波、继电器)

树莓派的接口&#xff1a; 大而简单的类别&#xff1a;IO口&#xff0c;input和output是相对于主控芯片来说的&#xff0c;是根据MCU和外设之间的关系将IO口的功能分为output和input。当IO作为input使用时外设有&#xff1a;人体传感器、烟雾传感器、火焰传感器、振动传感器等…