此代码基于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上测试了这个。
答案 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。