从插座到管道的接头冷冻

时间:2009-08-18 07:12:21

标签: c linux sockets pipe

此代码基于splice-fromnet.c and splice-cp.c从套接字到管道以及从管道到文件的拼接,但由于某种原因,对splice的第一次调用永远不会返回。

static size_t splice_from_net_to_file(int infd, int outfd)
{
    int p[2];
    size_t total = 0;

    if (pipe(p) == -1)
        return error("pipe");
    while (1) {
        int ret;
        ret = ssplice(infd, NULL, p[1], NULL, splice_size, 0);

        if (ret < 0) {
            close(p[0]);
            close(p[1]);
            return error("splice in pipe");
        }
        else if (!ret)
            break;
        while (ret > 0) {
            int written = ssplice(p[0], NULL, outfd, NULL, ret, 0);
            if (written <= 0) {
                close(p[0]);
                close(p[1]);
                return error("splice out pipe");
            }
            ret -= written;
            total += written;
        }       
    }
    close(p[0]);
    close(p[1]);
    return total;
}

我在linux 2.6.30上测试了这个。

4 个答案:

答案 0 :(得分:1)

你有可能没有在管道的另一侧启动监听器吗?

答案 1 :(得分:0)

splice_size在哪里被初始化?

答案 2 :(得分:0)

我认为这会阻止,因为写入时管道上没有读卡器。 您应该可以使用fork()解决此问题。

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

static size_t splice_from_net_to_file(int infd, int outfd)
{
    int p[2];
    pid_t fpid;
    size_t total = 0;

    if (pipe(p) == -1)
        return error("pipe");

    fpid = fork();
    if (fpid == -1)
        return error("fork");

    if (!fpid) /* child */
    {
        int ret;
        close(p[0]); /* don't need reading end */
        while ((ret = ssplice(infd, NULL, p[1], NULL, splice_size, 0)) > 0)
            ;
        close(p[1]);
        if (ret < 0 )
        {
            /* error("splice in pipe") */
            exit(-1);
        }
        exit(0);
    }
    else
    {
        /* parent */
        int ret;
        close(p[1]); /* no need for writing end */
        while ((ret = ssplice(p[0], NULL, outfd, NULL, splice_size, 0)) > 0)
            total += ret;
        close(p[0]);
        waitpid(fpid, NULL, 0);

        if (ret < 0)
        {
            return error("splice out pipe");
        }
    }

    return total;
}

答案 3 :(得分:0)

我想我刚刚遇到这个 - 这是由于2.6.32中修复的内核错误 - 有关详细信息,请参阅http://permalink.gmane.org/gmane.linux.network/138828

我在http://git.samba.org/?p=samba.git;a=commitdiff;h=e1459a237948c2c9b7da94e4ba0acc79b1cd8eca找到了一种解决方法 - 从

更改第一个splice()调用
ret = ssplice(infd, NULL, p[1], NULL, splice_size, 0);

ret = ssplice(infd, NULL, p[1], NULL, MIN(splice_size, 16384), 0);

所以你限制了你要求的数据量。

这使它适用于2.6.31。