IPC之FIFO

简介

             FIFO又被称为命名管道,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,一般的文件I/O函数都可以用于FIFO。

        打开一个FIFO时,非阻塞标志(O_NONBLOCK)产生下列影响:

    • 未指定O_NONBLOCK

        只读open()要阻塞到某个其他进程为写而打开此FIFO。类似的,只写open()要阻塞到某个其他进程为读而打开它。

    • 指定O_NONBLOCK

        只读open()立即返回。但是,如果没有进程已经为读而打开一个FIFO,那么只写open()将出错返回-1,其errno是ENXIO。

        基于O_NONBLOCK对FIFO操作的影响,一种比较好的操作FIFO的方式是以非阻塞的方式打开文件,然后以阻塞的方式读写文件或使用select。

        一个给定的FIFO有多个写进程是很常见的。这意味着如果不希望多个进程写的数据互相穿插,则需考虑原子操作,常量PIPE_BUF说明了可被原子地写到FIFO的最大数据量。

        FIFO有以下两种用途:

    1.     FIFO由shell命令使用以便将数据从一条管道线传送到另一条,为此不需要创建中间临时文件。
    2.     FIFO用于客户进程-服务器进程的应用程序中,以在客户进程和服务器进程中传递数据。


示例程序


阻塞版本


服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#define RECV_BUF_SIZE 1024
#define SEND_BUF_SIZE 1024
#define CONTENT_LEN 128
#define ARGUMENT_LEN 128

#define DATA_SEPARATOR ':'
#define SERVER_FIFO_PATH "/tmp/fifo_server"

int 	server_write_fd, server_read_fd, client_write_fd;
char    send_buf[SEND_BUF_SIZE];
char	content[CONTENT_LEN];
char	client_fifo_path[ARGUMENT_LEN];
char    recv_buf[RECV_BUF_SIZE];
char    send_buf[SEND_BUF_SIZE];

static int  fifo_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;

/*
 * create server fifo
 * success : 0 failed : -1
 */
int fifo_init(void)
{
	int 		ret;
	struct stat filestat;


	ret = stat(SERVER_FIFO_PATH, &filestat);
	if(ret == 0){
		if (unlink(SERVER_FIFO_PATH) < 0){
			perror("Cannot delete old MI fifo");
			return -1;
		}
	}else if(ret < 0 && errno != ENOENT){
		perror("MI FIFO stat failed");
		return -1;
	}

    if((mkfifo(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Create client fifo error");
      	return -1; 
    }

    if((chmod(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Chmod client fifo error");
		goto error;
    }

	return 0;

error:
   	remove(SERVER_FIFO_PATH);
	return -1;
		
}

/*
 * open server fifo
 * success : fd failed : -1
 */
int open_client_fifo(char *pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No server fifo to open\n");
        return -1;
    }

    client_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(client_write_fd < 0){
        perror("Can't open server fifo error");
        return -1;
    }

    if((flags = fcntl(client_write_fd, F_GETFL, 0)) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(client_write_fd, F_SETFL, flags) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    return 0;

error:
    close(client_write_fd);
    return -1;
}

/*
 * open server  fifo for reading
 * success : fd failed : -1
 */
int open_server_fifo(char * pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No client fifo to open");
        return -1;
    }

    server_read_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
    if(server_read_fd < 0){
        printf("Can't open client fifo for reading");
        return -1;
    }

    server_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(server_write_fd < 0){
        printf("Can't open client fifo for writing");
        return -1;
    }

    if((flags = fcntl(server_read_fd, F_GETFL, 0)) < 0){
        printf("Client fifo F_GETFL error");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(server_read_fd, F_SETFL, flags) < 0){
        printf("Client fifo F_SETFL error");
        goto error;
    }

    return 0;

error:
    close(server_read_fd);
    close(server_write_fd);
    return -1;
}

int data_parse(void)
{
	char	*p, *postion;
	
	p = recv_buf;


	if(*p != DATA_SEPARATOR){
		printf("command must begin with %c\n", DATA_SEPARATOR);
		return -1;
	}
	p++;

	postion = strchr(p, DATA_SEPARATOR);
	if(postion == NULL){
		printf("file separator missing in fifo command\n");
		return -1;
	}
	strncpy(client_fifo_path, p, postion - p);

	p = ++postion;
	strncpy(content, p, strlen(p));

	return 0;
}

int main(int argc, char *argv[])
{

    int     ret;

    if(fifo_init()){
		return -1;
    }

    if(open_server_fifo(SERVER_FIFO_PATH)){
		goto error;
    }

   	while(1){
		memset(recv_buf, 0, RECV_BUF_SIZE);
		if((ret = read(server_read_fd, recv_buf, RECV_BUF_SIZE)) > 0){

			if(data_parse()){
				continue;
			}
			printf("Receive data from <%s> : %s\n",
					client_fifo_path, content);

    		if(open_client_fifo(client_fifo_path)){
				continue;
    		}

			sprintf(send_buf, "hello, %s\n", client_fifo_path);
			ret = write(client_write_fd, send_buf, strlen(send_buf));
			if(ret < 0){
				perror("Write data to client fifo error");
				continue;
			}
		}
	}

	exit(EXIT_SUCCESS);

error:
	remove(SERVER_FIFO_PATH);
	exit(EXIT_FAILURE);
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#define SERVER_FIFO_PATH "/tmp/fifo_server"
#define CLIENT_FIFO_PATH "/tmp/fifo_client_%d"

#define SEND_BUF_SIZE 1024
#define RECV_BUF_SIZE 1024
#define CLIENT_FIFO_SIZE 128

int 	server_write_fd, client_read_fd, client_write_fd;
char	client_fifo[CLIENT_FIFO_SIZE];
char    send_buf[SEND_BUF_SIZE];

static int  fifo_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;

/*
 * create client fifo
 * success : 0 failed : -1
 */
int fifo_init(void)
{
	int 		ret;
	struct stat filestat;

	memset(client_fifo, 0, CLIENT_FIFO_SIZE);
	sprintf(client_fifo, CLIENT_FIFO_PATH, getpid());

	ret = stat(client_fifo, &filestat);
	if(ret == 0){
		if (unlink(client_fifo) < 0){
			perror("Cannot delete old MI fifo");
			return -1;
		}
	}else if(ret < 0 && errno != ENOENT){
		perror("MI FIFO stat failed");
		return -1;
	}

    if((mkfifo(client_fifo, fifo_mode) < 0)){
        perror("Create client fifo error");
      	return -1; 
    }

    if((chmod(client_fifo, fifo_mode) < 0)){
        perror("Chmod client fifo error");
		goto error;
    }

	return 0;

error:
   	remove(client_fifo);
	return -1;
		
}

/*
 * open server fifo for writing
 * success : fd failed : -1
 */
int open_server_fifo(char *pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No server fifo to open\n");
        return -1;
    }

    server_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(server_write_fd < 0){
        perror("Can't open server fifo error");
        return -1;
    }

    if((flags = fcntl(server_write_fd, F_GETFL, 0)) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(server_write_fd, F_SETFL, flags) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    return 0;

error:
    close(server_write_fd);
    return -1;
}

/*
 * open client fifo
 * success : fd failed : -1
 */
int open_client_fifo(char * pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No client fifo to open.\n");
        return -1;
    }

    client_read_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
    if(client_read_fd < 0){
        printf("Can't open client fifo for reading");
        return -1;
    }

    client_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(client_write_fd < 0){
        printf("Can't open client fifo for writing\n");
        return -1;
    }

    if((flags = fcntl(client_read_fd, F_GETFL, 0)) < 0){
        printf("Client fifo F_GETFL error.\n");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(client_read_fd, F_SETFL, flags) < 0){
        printf("Client fifo F_SETFL error.\n");
        goto error;
    }

    return 0;

error:
    close(client_read_fd);
    close(client_write_fd);
    return -1;
}


int main(int argc, char *argv[])
{

    int     ret;
    char    recv_buf[RECV_BUF_SIZE];

    if(fifo_init()){
		return -1;
    }

    if(open_client_fifo(client_fifo)){
		goto error1;
    }

    if(open_server_fifo(SERVER_FIFO_PATH)){
		goto error2;
    }

	sprintf(send_buf, ":%s:hello, server.", client_fifo);
    ret = write(server_write_fd, send_buf, strlen(send_buf));
    if(ret < 0){
        perror("Write data to server fifo error");
		goto error3;
    }

	memset(recv_buf, 0, RECV_BUF_SIZE);
   	if((ret = read(client_read_fd, recv_buf, RECV_BUF_SIZE)) > 0){
		printf("Receive data form server : %s", recv_buf);
	}

   	close(client_read_fd);
  	close(server_write_fd);
   	remove(client_fifo);

	exit(EXIT_SUCCESS);

error3:
	close(server_write_fd);
error2:
	close(client_read_fd);
	close(client_write_fd);
error1:
   	remove(client_fifo);
	
	exit(EXIT_FAILURE);	
}

select版本


服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#define RECV_BUF_SIZE 1024
#define SEND_BUF_SIZE 1024
#define CONTENT_LEN 128
#define ARGUMENT_LEN 128

#define DATA_SEPARATOR ':'
#define SERVER_FIFO_PATH "/tmp/fifo_server"

int 	server_write_fd, server_read_fd, client_write_fd;
char    send_buf[SEND_BUF_SIZE];
char	content[CONTENT_LEN];
char	client_fifo_path[ARGUMENT_LEN];
char    recv_buf[RECV_BUF_SIZE];
char    send_buf[SEND_BUF_SIZE];

static int  fifo_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;

/*
 * create server fifo
 * success : 0 failed : -1
 */
int fifo_init(void)
{
	int 		ret;
	struct stat filestat;


	ret = stat(SERVER_FIFO_PATH, &filestat);
	if(ret == 0){
		if (unlink(SERVER_FIFO_PATH) < 0){
			perror("Cannot delete old MI fifo");
			return -1;
		}
	}else if(ret < 0 && errno != ENOENT){
		perror("MI FIFO stat failed");
		return -1;
	}

    if((mkfifo(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Create client fifo error");
      	return -1; 
    }

    if((chmod(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Chmod client fifo error");
		goto error;
    }

	return 0;

error:
   	remove(SERVER_FIFO_PATH);
	return -1;
		
}

/*
 * open server fifo
 * success : fd failed : -1
 */
int open_client_fifo(char *pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No server fifo to open\n");
        return -1;
    }

    client_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(client_write_fd < 0){
        perror("Can't open server fifo error");
        return -1;
    }

    if((flags = fcntl(client_write_fd, F_GETFL, 0)) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(client_write_fd, F_SETFL, flags) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    return 0;

error:
    close(client_write_fd);
    return -1;
}

/*
 * open server  fifo for reading
 * success : fd failed : -1
 */
int open_server_fifo(char * pipe_name)
{
    //int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No client fifo to open");
        return -1;
    }

    server_read_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
    if(server_read_fd < 0){
        printf("Can't open client fifo for reading");
        return -1;
    }

    return 0;
}

int data_parse(void)
{
	char	*p, *postion;
	
	p = recv_buf;


	if(*p != DATA_SEPARATOR){
		printf("command must begin with %c\n", DATA_SEPARATOR);
		return -1;
	}
	p++;

	postion = strchr(p, DATA_SEPARATOR);
	if(postion == NULL){
		printf("file separator missing in fifo command\n");
		return -1;
	}
	strncpy(client_fifo_path, p, postion - p);

	p = ++postion;
	strncpy(content, p, strlen(p));

	return 0;
}

int main(int argc, char *argv[])
{

    int     ret, maxfd;
	fd_set	set, read_set;
	struct	timeval timeout;

    if(fifo_init()){
		return -1;
    }

    if(open_server_fifo(SERVER_FIFO_PATH)){
		goto error;
    }

	FD_ZERO(&set);
	FD_SET(server_read_fd, &set); 
	maxfd = server_read_fd + 1;

   	while(1){
		read_set = set;
		timeout.tv_sec = 2;
		timeout.tv_usec = 0;

		memset(recv_buf, 0, RECV_BUF_SIZE);
		ret = select(maxfd, &read_set, NULL, NULL, &timeout);
		switch(ret){
			case 0:
				continue;
			case -1:
				perror("select");
				continue;
			default:
				if(FD_ISSET(server_read_fd, &read_set)){
					if((ret = read(server_read_fd,
						recv_buf, RECV_BUF_SIZE)) > 0){

						if(data_parse()){
							continue;
						}
						printf("Receive data from <%s> : %s\n",
								client_fifo_path, content);

    					if(open_client_fifo(client_fifo_path)){
							continue;
    					}

						sprintf(send_buf, "hello, %s\n", client_fifo_path);
						ret = write(client_write_fd, 
									send_buf, strlen(send_buf));
						if(ret < 0){
							perror("Write data to client fifo error");
							continue;
						}
					}
				}
		}
	}

	remove(SERVER_FIFO_PATH);
	exit(EXIT_SUCCESS);

error:
	remove(SERVER_FIFO_PATH);
	exit(EXIT_FAILURE);
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#define RECV_BUF_SIZE 1024
#define SEND_BUF_SIZE 1024
#define CONTENT_LEN 128
#define ARGUMENT_LEN 128

#define DATA_SEPARATOR ':'
#define SERVER_FIFO_PATH "/tmp/fifo_server"

int 	server_write_fd, server_read_fd, client_write_fd;
char    send_buf[SEND_BUF_SIZE];
char	content[CONTENT_LEN];
char	client_fifo_path[ARGUMENT_LEN];
char    recv_buf[RECV_BUF_SIZE];
char    send_buf[SEND_BUF_SIZE];

static int  fifo_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;

/*
 * create server fifo
 * success : 0 failed : -1
 */
int fifo_init(void)
{
	int 		ret;
	struct stat filestat;


	ret = stat(SERVER_FIFO_PATH, &filestat);
	if(ret == 0){
		if (unlink(SERVER_FIFO_PATH) < 0){
			perror("Cannot delete old MI fifo");
			return -1;
		}
	}else if(ret < 0 && errno != ENOENT){
		perror("MI FIFO stat failed");
		return -1;
	}

    if((mkfifo(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Create client fifo error");
      	return -1; 
    }

    if((chmod(SERVER_FIFO_PATH, fifo_mode) < 0)){
        perror("Chmod client fifo error");
		goto error;
    }

	return 0;

error:
   	remove(SERVER_FIFO_PATH);
	return -1;
		
}

/*
 * open server fifo
 * success : fd failed : -1
 */
int open_client_fifo(char *pipe_name)
{
    int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No server fifo to open\n");
        return -1;
    }

    client_write_fd = open(pipe_name, O_WRONLY|O_NONBLOCK);
    if(client_write_fd < 0){
        perror("Can't open server fifo error");
        return -1;
    }

    if((flags = fcntl(client_write_fd, F_GETFL, 0)) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    flags&=~O_NONBLOCK;

    if(fcntl(client_write_fd, F_SETFL, flags) < 0){
        perror("Server fifo F_GETFL error");
        goto error;
    }

    return 0;

error:
    close(client_write_fd);
    return -1;
}

/*
 * open server  fifo for reading
 * success : fd failed : -1
 */
int open_server_fifo(char * pipe_name)
{
    //int     flags;

    if(!pipe_name || *pipe_name == 0){
        printf("No client fifo to open");
        return -1;
    }

    server_read_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
    if(server_read_fd < 0){
        printf("Can't open client fifo for reading");
        return -1;
    }

    return 0;
}

int data_parse(void)
{
	char	*p, *postion;
	
	p = recv_buf;


	if(*p != DATA_SEPARATOR){
		printf("command must begin with %c\n", DATA_SEPARATOR);
		return -1;
	}
	p++;

	postion = strchr(p, DATA_SEPARATOR);
	if(postion == NULL){
		printf("file separator missing in fifo command\n");
		return -1;
	}
	strncpy(client_fifo_path, p, postion - p);

	p = ++postion;
	strncpy(content, p, strlen(p));

	return 0;
}

int main(int argc, char *argv[])
{

    int     ret, maxfd;
	fd_set	set, read_set;
	struct	timeval timeout;

    if(fifo_init()){
		return -1;
    }

    if(open_server_fifo(SERVER_FIFO_PATH)){
		goto error;
    }

	FD_ZERO(&set);
	FD_SET(server_read_fd, &set); 
	maxfd = server_read_fd + 1;

   	while(1){
		read_set = set;
		timeout.tv_sec = 2;
		timeout.tv_usec = 0;

		memset(recv_buf, 0, RECV_BUF_SIZE);
		ret = select(maxfd, &read_set, NULL, NULL, &timeout);
		switch(ret){
			case 0:
				continue;
			case -1:
				perror("select");
				continue;
			default:
				if(FD_ISSET(server_read_fd, &read_set)){
					if((ret = read(server_read_fd,
						recv_buf, RECV_BUF_SIZE)) > 0){

						if(data_parse()){
							continue;
						}
						printf("Receive data from <%s> : %s\n",
								client_fifo_path, content);

    					if(open_client_fifo(client_fifo_path)){
							continue;
    					}

						sprintf(send_buf, "hello, %s\n", client_fifo_path);
						ret = write(client_write_fd, 
									send_buf, strlen(send_buf));
						if(ret < 0){
							perror("Write data to client fifo error");
							continue;
						}
					}
				}
		}
	}

	remove(SERVER_FIFO_PATH);
	exit(EXIT_SUCCESS);

error:
	remove(SERVER_FIFO_PATH);
	exit(EXIT_FAILURE);
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值