我一直在编写一个有趣的程序,可以在Linux上用C语言通过TCP传输文件.程序从套接字读取文件并将其写入文件(反之亦然).我最初使用读/写和程序正常工作,但后来我学习了拼接,并想尝试一下.
我用splice编写的代码在从stdin(重定向文件)读取并写入TCP套接字时非常有效,但在从套接字读取并写入stdout时,会立即将splice设置errno设置为EINVAL.手册页指出当两个描述符都不是管道(不是这种情况)时,EINVAL被设置,为无法搜索的流传递偏移量(没有传递偏移量),或文件系统不支持拼接,这导致我我的问题:这是否意味着TCP可以拼接的管道,而不是到?
我包括下面的代码(减去错误处理代码),希望我做错了.它主要基于维基百科的拼接示例.
static void splice_all(int from, int to, long long bytes)
{
long long bytes_remaining;
long result;
bytes_remaining = bytes;
while (bytes_remaining > 0) {
result = splice(
from, NULL,
to, NULL,
bytes_remaining,
SPLICE_F_MOVE | SPLICE_F_MORE
);
if (result == -1)
die("splice_all: splice");
bytes_remaining -= result;
}
}
static void transfer(int from, int to, long long bytes)
{
int result;
int pipes[2];
result = pipe(pipes);
if (result == -1)
die("transfer: pipe"); …
Run Code Online (Sandbox Code Playgroud) 我写的TCP中继服务器就像对等路由器(超级节点)一样工作.
最简单的情况是两个打开的套接字和它们之间的数据中继:
clientA <---> server <---> clientB
然而,服务器必须服务大约2000个这样的AB对,即.4000个插座......
userland中有两个众所周知的数据流中继实现(基于socketA.recv() - > socketB.send()和socketB.recv() - > socketA.send()):
我使用线程,所以在最坏的情况下服务器创建2*2000个线程!我不得不限制堆栈大小,它的工作原理,但它是正确的解决方案吗?
我的问题的核心:
有没有办法避免用户区中两个套接字之间的活动数据中继?
似乎有一种被动的方式.例如,我可以从每个套接字创建文件描述符,创建两个管道并使用dup2() - 与stdin/out重定向相同的方法.然后两个线程对数据中继没用,可以完成/关闭. 问题是服务器是否应该关闭套接字和管道以及如何知道管道何时损坏以记录事实?
我也发现了"套接字对",但我不确定它是否符合我的目的.
你会建议什么解决方案来卸载用户空间并限制线程数量?
一些额外的解释:
感谢Gerhard Rieger,我有一个提示:
我知道有两种内核空间方法可以避免在用户空间中进行读/写,recv/send:
- 发送文件
- 拼接
两者都有关于文件描述符类型的限制.
dup2无助于在内核中执行某些操作,AFAIK.
手册页:splice(2) splice(2) vmsplice(2) sendfile(2) tee(2)
相关链接: