C 从命名管道读取

C 从命名管道读取,c,linux,posix,named-pipes,C,Linux,Posix,Named Pipes,我必须实现一个“打印服务器”。我有1个客户端文件和1个服务器文件: #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> int get_line( char *dest, int

我必须实现一个“打印服务器”。我有1个客户端文件和1个服务器文件:

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

int get_line( char *dest, int size );

#define MAX 1024

void main ()
{
    char const *pipe = "printservers";
    char buffer[MAX];
    int fd;

    get_line( buffer, MAX );

    if( mkfifo( pipe, 0666 ) < 0 )
    {
        printf( "Cannot create a pipe\n" );
        exit( EXIT_FAILURE );
    }

    fd = open( pipe, O_WRONLY );

    write( fd, buffer, MAX );

    close( fd );

    //unlink( pipe );

}

int get_line( char *dest, int size )
{
    int c, i;
    for( i = 0; i < size - 1 && ( c = getchar() ) != EOF && c != '\n'; ++i )
        dest[i] = c;
    if( c == '\n' )
    {
        dest[i] = c;
        ++i;
    }
    dest[i] = '\0';
    return i;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int get_行(char*dest,int size);
#定义最大1024
空干管()
{
char const*pipe=“printservers”;
字符缓冲区[MAX];
int-fd;
获取_行(缓冲区,最大值);
如果(mkfifo(管道,0666)<0)
{
printf(“无法创建管道\n”);
退出(退出失败);
}
fd=开放式(仅适用于管道);
写入(fd、缓冲区、最大值);
关闭(fd);
//断开(管道)连接;
}
int get_行(char*dest,int size)
{
int c,i;
对于(i=0;i
这就是客户机,它从标准输入中读取一行并写入 名为printservers的命名管道。这正是我们想要的

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

#define MAX_BUF 1024
#define MAX_PID 8

int main()
{
    int fd;
    char * myfifo = "printservers";
    char buf[MAX_BUF];

    /* open, read, and display the message from the FIFO */
    fd = open( myfifo, O_RDONLY );
    while( 1 )
    {
        if( read( fd, buf, MAX_BUF ) > 0 )
            printf("Received: %s\n", buf);
    }
    close(fd);

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#定义最大值为1024
#定义最大PID 8
int main()
{
int-fd;
char*myfifo=“打印服务器”;
char buf[MAX_buf];
/*打开、读取并显示来自FIFO的信息*/
fd=打开(仅限myfifo、Ordu);
而(1)
{
如果(读取(fd、buf、MAX_buf)>0)
printf(“收到:%s\n”,buf);
}
关闭(fd);
返回0;
}
这是从管道读取的服务器。但它不适用于while循环。如果我从客户端发送消息,将打印第一条消息,但忽略以下消息。 有人能帮我解决这个问题吗? 谢谢
Patrik

服务器的while循环中存在编码错误-即使出现错误或服务器在FIFO上接收到eof,服务器也永远不会退出循环。应该改成这样:

while(1)
{
    if((bytesread = read( fd, buf, MAX_BUF - 1)) > 0)
    {
        buf[bytesread] = '\0';
        printf("Received: %s\n", buf);
    }
    else
        break;
}
您的另一个问题是,您的客户机发送一条线路,然后关闭FIFO。服务器读取直到EOF。所以它将读取单行,然后点击EOF,因为客户端关闭了。这是完全正常的

当您希望您的服务器向多个客户端提供服务时,问题就出现了。在这种情况下,你不想在每个客户都关闭了它的终端之后就停止阅读。语义是这样的,服务器只有在最后一个客户端关闭后才会看到EOF。因此,适应处理多个客户机的服务器的简单方法是以读/写方式打开服务器端FIFO。然后总会有一个“写入器”,即服务器本身,打开FIFO的写入端。这将阻止服务器看到EOF,直到您决定关闭它

第二个问题是,您需要在循环中读写。您不能保证在一次通话中填写完整的数据请求


此外,让客户端创建服务器读取的FIFO也是一种奇怪的方法。通常,您希望服务器创建一个已知的FIFO,以便客户端连接到该FIFO。

您是否为每次提交调用客户端进程?如果是这样,您应该在服务器中创建fifo,使其每次都是相同的实体。您的服务器应该按预期工作-尝试单独运行它,并在另一个终端上向fifo回显一些内容。但是,在使用
printf
@ace谢谢ace,这解决了我的问题。@Amardeep有什么区别吗?因为我试过了,它在两方面都有效。你忽略了一些重要的事情。使用如图所示的代码,第一个客户端之后的每个客户端都会遇到mkfifo()EEXIST故障,并使用
“无法创建管道”
退出。我怀疑您实际上是在每次客户端运行结束时取消FIFO的链接()(正如您注释的代码所示):您重新运行客户端,它在open()上阻塞,直到您运行服务器,然后第一个客户端取消了FIFO的链接,让可怜的服务器永远陷入紧张而无声的读取()中/EOF循环对一个未链接的FIFO没有希望未来的输入。谢谢你的回答。如果我使用“write(1,buf,size)”,其中size是read的返回值,则在另一个终端上只显示1个字符。如果我使用“write(1,buf,BUFMAXSIZE)”,则它会将消息加上垃圾(一些符号)写入。你能解释一下是怎么回事吗?不知道你在做什么。我建议您在客户机中编写
strlen
字节,而不是编写字符串的最大字节数以及其后的buf中的任何垃圾。嗯,这实际上不是他的问题(他没有问题)?发布的代码不会在EOF上终止-它停留在一个紧密的read()循环中。正如我上面所说的,我认为我们没有看到真正完整的代码。@pilcrow,你说得对。我错过了一会儿。我专注于为每个客户发送一条消息。有机会我会修改答案的。