进程间通信-FIFO

FIFO 也称为“命名管道”。它在文件系统中有一个相应的文件,称为管道文件。FIFO文件可以通过mkfifo()函数创建。在FIFO文件创建之后,任何一个具有适当权限的进程都可以打开它,从文件描述符中读取或写入数据。

    #include <sys/types.h>  
    #include <sys/stat.h>  
    int mkfifo(const char * pathname, mode_t mode)  

注意:在程序结束后,系统不会自动删除FIFO文件。若要删除,可以用unlink()函数删除

打开规则

如果当前打开操作是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志);或者,成功返回(当前打开操作没有设置阻塞标志)。

如果当前打开操作是为写而打开FIFO时,如果已经有相应进程为读而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。

 

注意:写操作打开FIFO时,如果没有进程为读而打开FIFO,非阻塞状态将返回INSIO错误;阻塞的话将阻塞到有进程为读打开FIFO.

         读操作打开FIFO时,如果没有进程为写打开FIFO,非阻塞状态返回成功;阻塞的话将阻塞到有进程为写而打开FIFO.

读写规则

约定:如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。

  • 如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞。对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。
  • 对于设置了阻塞标志的读操作说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。
  • 读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。
  • 如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。

注:如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。

向FIFO中写入数据:

约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。

对于设置了阻塞标志的写操作:

  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

对于没有设置阻塞标志的写操作:

  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写;
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

/*define a function pid_printf*/
void pid_printf(char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    printf("[%d]%d:", getpid(),__LINE__);
    vprintf(format, ap);
}

#define FIFO_PATH "/tmp/fifo_test"

char end = 'a';
void server()
{
#if 1
    char buf[20]="hellohehelloworld!";
    int fd;
    if(mkfifo(FIFO_PATH, 0600))
    {
        perror("mkfifo");
    }
    pid_printf("The server is writing...\n");
    fd = open(FIFO_PATH, O_WRONLY);
    pid_printf("fd=[%d] errno=[%d]\n", fd, errno);
    
    int i;
    for(i=0; i < 20; ++i)
    {
        sleep(2);
        buf[18] = end++;
        if(end == 'z'+1)
            end = 'a';
        write(fd, buf, sizeof(buf));
        pid_printf("write=[%s]\n", buf);
    }
    
    close(fd);
    sleep(9);
    unlink(FIFO_PATH);
    
    
#endif
#if 0
    char buf[256]={0};
    int fd;
    int count, status;
    if(mkfifo(FIFO_PATH, 0660))
    {
        perror("mkfifo");
    }
    fd=open(FIFO_PATH, O_RDONLY);
    while(1)
    {
        count =0;
        while(count< sizeof(buf)-1)
        {
            status=read(fd, buf+count, 1);
            if(status<1)
            {
                pid_printf("read eof,server exit\n");
                goto server_exit;
            }
            if(buf[count]=='\n')
            {
                buf[count] = 0;
                break;
            }
            count++;
        }
        pid_printf("receive [%s]\n", buf);
    }
server_exit:
    close(fd);
    unlink(FIFO_PATH);
#endif
}

void client()
{
#if 1
    int fd;
    char buf[20]="0";
    
    fd=open(FIFO_PATH, O_RDONLY);
    pid_printf("client is reading...\n");
    
    int i;
    for(i=0; i<20; ++i)
    {
        sleep(3);
        read(fd, buf, sizeof(buf));
        pid_printf("read=[%s]\n", buf);
    }
    close(fd);
#endif
#if 0
    int fd;
    char buf[256];
    fd=open(FIFO_PATH, O_WRONLY);
    pid_printf("the client is ready...\n");
    while(fgets(buf, sizeof(buf), stdin)!=NULL)
    {
        write(fd, buf, strlen(buf));
    }
    pid_printf("client exit...\n");
    close(fd);
#endif
}

int main(int argc, char *argv[])
{
    if(argc < 2)
        server();
    else
        client();
        
    return 0;
}










注意:程序有参数时运行客户端,否则运行服务端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值