进程间通信-信号-pipe-fifo

有名管道FIFO

无名管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服。
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可
以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意
的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如
lseek()等文件定位操作。
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小)
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等

代码实践

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

int main()
{
	int res = mkfifo("/tmp/myfifo", 0777);
	if (res == 0) {
		printf("FIFO created \n");
	}
	exit(EXIT_SUCCESS);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF


int main()
{
	int pipe_fd;
	int res;

	int open_mode = O_RDONLY;
	char buffer[BUFFER_SIZE + 1];
	int bytes = 0;

	memset(buffer, 0, sizeof(buffer));

	printf("Process %d opeining FIFO O_RDONLY \n", getpid());
	pipe_fd = open(FIFO_NAME, open_mode);
	printf("Process %d result %d\n", getpid(), pipe_fd);

	if (pipe_fd != -1) {
		do {
			res = read(pipe_fd, buffer, BUFFER_SIZE);
			bytes += res;
		} while (res > 0);
		close(pipe_fd);
	} else {
		exit(EXIT_FAILURE);
	}

	printf("Process %d finished, %d bytes read\n", getpid(), bytes);
	exit(EXIT_SUCCESS);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)

int main()
{
	int pipe_fd;
	int res;
	int open_mode = O_WRONLY;

	int bytes = 0;
	char buffer[BUFFER_SIZE + 1];

	if (access(FIFO_NAME, F_OK) == -1) {
		res = mkfifo(FIFO_NAME, 0777);
		if (res != 0) {
			fprintf(stderr, "Could not create fifo %s \n",
				FIFO_NAME);
			exit(EXIT_FAILURE);
		}
	}

	printf("Process %d opening FIFO O_WRONLY\n", getpid());
	pipe_fd = open(FIFO_NAME, open_mode);
	printf("Process %d result %d\n", getpid(), pipe_fd);

	if (pipe_fd != -1) {
		while (bytes < TEN_MEG) {
			res = write(pipe_fd, buffer, BUFFER_SIZE);
			if (res == -1) {
				fprintf(stderr, "Write error on pipe\n");
				exit(EXIT_FAILURE);
			}
			bytes += res;
		}
		close(pipe_fd);
	} else {
		exit(EXIT_FAILURE);
	}

	printf("Process %d finish\n", getpid());
	exit(EXIT_SUCCESS);
}

管道PIPE

  • 匿名管道是右内核管理的一个缓冲区,相当于我们放入内存的中一个纸条。匿名管道的一端连接一个进程的输出。这个进程会向管道中放入信息。
  • 匿名管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。
  • 一个缓存区不需要很大,它被设计成为唤醒的数据结构,以便管道可以被循环利用。
  • 当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。
  • 当管道被放满信息的时候,尝试放入信息的进程就会等待,直到另一端的进程取出信息。
  • 两个进程都终结的时候,管道也会自动消失。
  • 从原理上,匿名管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。
  • 最开始的时候,上面的两个箭头都连接到同一个进程Process 1上(连接在Process 1上的两个箭头)。
  • 当fork复制进程的时候,会将这两个连接也复制到新的进程(Process 2)。
  • 随后,每个进程关闭在自己不需要的一个连接(两个黑色的箭头被关闭;Process 1关闭从PIPE来的输入连接,Process 2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了上图的PIPE。

代码实践

#include<stdio.h>

main( int ac, char *av[] )
{
	int	i;

	printf("Number of args: %d, Args are:\n", ac);
	for(i=0;i<ac;i++)
		printf("args[%d] %s\n", i, av[i]);

	fprintf(stderr,"This message is sent to stderr.\n");
}

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

#define	oops(m,x)	{ perror(m); exit(x); }

int main(int ac, char **av)
{
	int	thepipe[2],
		newfd,
		pid;

	if ( ac != 3 ){
		fprintf(stderr, "usage: pipe cmd1 cmd2\n");
		exit(1);
	}
	if ( pipe( thepipe ) == -1 )
		oops("Cannot get a pipe", 1);

	if ( (pid = fork()) == -1 )
		oops("Cannot fork", 2);

	if ( pid > 0 ){
		close(thepipe[1]);

		if ( dup2(thepipe[0], 0) == -1 )
			oops("could not redirect stdin",3);

		close(thepipe[0]);
		execlp( av[2], av[2], NULL);
		oops(av[2], 4);
	}

	close(thepipe[0]);

	if ( dup2(thepipe[1], 1) == -1 )
		oops("could not redirect stdout", 4);

	close(thepipe[1]);
	execlp( av[1], av[1], NULL);
	oops(av[1], 5);
}

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main()
{
	int	len, i, apipe[2];
	char	buf[BUFSIZ];

	if ( pipe ( apipe ) == -1 ){
		perror("could not make pipe");
		exit(1);
	}
	printf("Got a pipe! It is file descriptors: { %d %d }\n",
							apipe[0], apipe[1]);


	while ( fgets(buf, BUFSIZ, stdin) ){
		len = strlen( buf );
		if (  write( apipe[1], buf, len) != len ){
			perror("writing to pipe");
			break;
		}
		for ( i = 0 ; i<len ; i++ )
			buf[i] = 'X' ;
		len = read( apipe[0], buf, BUFSIZ ) ;
		if ( len == -1 ){
			perror("reading from pipe");
			break;
		}
		if ( write( 1 , buf, len ) != len ){
			perror("writing to stdout");
			break;
		}
	}
}

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>


#define	CHILD_MESS	"I want a cookie\n"
#define	PAR_MESS	"testing..\n"
#define	oops(m,x)	{ perror(m); exit(x); }

main()
{
	int	pipefd[2];
	int	len;
	char	buf[BUFSIZ];
	int	read_len;

	if ( pipe( pipefd ) == -1 )
		oops("cannot get a pipe", 1);

	switch( fork() ){
		case -1:
			oops("cannot fork", 2);

		case 0:
			len = strlen(CHILD_MESS);
			while ( 1 ){
				if (write( pipefd[1], CHILD_MESS, len) != len )
					oops("write", 3);
				sleep(5);
			}

		default:
			len = strlen( PAR_MESS );
			while ( 1 ){
				if ( write( pipefd[1], PAR_MESS, len)!=len )
					oops("write", 4);
				sleep(1);
				read_len = read( pipefd[0], buf, BUFSIZ );
				if ( read_len <= 0 )
					break;
				write( 1 , buf, read_len );
			}
	}
}

#include<stdio.h>
#include<fcntl.h>

int main()
{
	int	fd ;
	char	line[100];

	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );

	close(0);
	fd = open("/etc/passwd", O_RDONLY);
	if ( fd != 0 ){
		fprintf(stderr,"Could not open data as fd 0\n");
		exit(1);
	}

	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
}

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>

//#define	CLOSE_DUP
//#define	USE_DUP2

main()
{
	int	fd ;
	int	newfd;
	char	line[100];

	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );

	fd = open("data", O_RDONLY);
#ifdef CLOSE_DUP
	close(0);
	newfd = dup(fd);
#else
	newfd = dup2(fd,0);
#endif
	if ( newfd != 0 ){
		fprintf(stderr,"Could not duplicate fd to 0\n");
		exit(1);
	}
	close(fd);

	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
	fgets( line, 100, stdin ); printf("%s", line );
}

#include <unistd.h>

int main()
{
	char *buf = "abcde\n";
	write(0, buf, 6);
}

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
	int	pid ;
	int	fd;

	printf("About to run who into a file\n");

	if( (pid = fork() ) == -1 ){
		perror("fork"); exit(1);
	}
	if ( pid == 0 ){
		close(1);				/* close, */
		fd = creat( "userlist", 0644 );		/* then open */
		execlp( "who", "who", NULL );		/* and run	*/
		perror("execlp");
		exit(1);
	}
	if ( pid != 0 ){
		wait(NULL);
		printf("Done running who.  results in userlist\n");
	}

	return 0;
}

signal

代码实践

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#define	INPUTLEN	100
void inthandler();
int main()
{
	struct sigaction newhandler;
	sigset_t blocked;
	char x[INPUTLEN];
	newhandler.sa_handler = inthandler;
	newhandler.sa_flags = SA_RESTART|SA_NODEFER
		|SA_RESETHAND;
	sigemptyset(&blocked);
	sigaddset(&blocked, SIGQUIT);
	newhandler.sa_mask = blocked;
	if (sigaction(SIGINT, &newhandler, NULL) == -1)
		perror("sigaction");
	else
		while (1) {
			fgets(x, INPUTLEN, stdin);
			printf("input: %s", x);
		}
	return 0;
}
void inthandler(int s)
{
	printf("Called with signal %d\n", s);
	sleep(s * 4);
	printf("done handling signal %d\n", s);
}

#include <unistd.h>
#include <signal.h>
#include <stdio.h>

void sig_alrm( int signo )
{
	/*do nothing*/
}

unsigned int mysleep(unsigned int nsecs)
{
	struct sigaction newact, oldact;
	unsigned int unslept;

	newact.sa_handler = sig_alrm;
	sigemptyset( &newact.sa_mask );
	newact.sa_flags = 0;
	sigaction( SIGALRM, &newact, &oldact );

	alarm( nsecs );
	pause();

	unslept = alarm ( 0 );
	sigaction( SIGALRM, &oldact, NULL );

	return unslept;
}

int main( void )
{
	while( 1 )
	{
		mysleep( 2 );
		printf( "Two seconds passed\n" );
	}

	return 0;
}

#include<stdio.h>
#include<signal.h>
void	f(int);
int main()
{
	int	i;
	signal( SIGINT, f );
	for(i=0; i<5; i++ ){
		printf("hello\n");
		sleep(2);
	}

	return 0;
}

void f(int signum)
{
	printf("OUCH!\n");
}

#include<stdio.h>
#include<signal.h>

main()
{
	signal( SIGINT, SIG_IGN );

	printf("you can't stop me!\n");
	while( 1 )
	{
		sleep(1);
		printf("haha\n");
	}
}

#include<stdio.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>

#define	INPUTLEN	100

int main(int argc, char *argv[])
{
	void inthandler(int);
	void quithandler(int);
	char input[INPUTLEN];
	int nchars;

	signal(SIGINT, inthandler);//^C
	signal(SIGQUIT, quithandler);//^\

	do {
		printf("\nType a message\n");
		nchars = read(0, input, (INPUTLEN - 1));
		if (nchars == -1)
			perror("read returned an error");
		else {
			input[nchars] = '\0';
			printf("You typed: %s", input);
		}
	}
	while (strncmp(input, "quit", 4) != 0);
	return 0;
}

void inthandler(int s)
{
	printf(" Received signal %d .. waiting\n", s);
	sleep(2);
	printf("  Leaving inthandler \n");
}

void quithandler(int s)
{
	printf(" Received signal %d .. waiting\n", s);
	sleep(3);
	printf("  Leaving quithandler \n");
}

参考

参考链接:https://www.jianshu.com/p/2eb7db04909c
参考链接:https://blog.csdn.net/dxpqxb/article/details/78251551

posted on 2022-11-13 18:33  20201310寸头  阅读(26)  评论(0编辑  收藏  举报