Я написал небольшую программу для развлечения, которая передает файлы по TCP на C в Linux. Программа читает файл из сокета и записывает его в файл (или наоборот). Первоначально я использовал чтение / запись, и программа работала правильно, но затем я узнал о splice и хотел попробовать.
Код, который я написал с помощью splice, отлично работает при чтении из stdin (перенаправленный файл) и записи в сокет TCP, но сразу завершается неудачно, когда splice устанавливает errno в EINVAL при чтении из сокета и записи в stdout. Страница man утверждает, что EINVAL устанавливается, когда ни один дескриптор не является каналом (не регистром), смещение передается для потока, который не может быть найден (без смещений), или файловая система не поддерживает сплайсинг, что приводит меня на мой вопрос: означает ли это, что TCP может соединять от канала, но не до ?
Я включил приведенный ниже код (за исключением кода обработки ошибок) в надежде, что я только что сделал что-то не так. Он основан на примере Wikipedia для соединения .
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");
splice_all(from, pipes[1], bytes);
splice_all(pipes[0], to, bytes);
close(from);
close(pipes[1]);
close(pipes[0]);
close(to);
}
С другой стороны, я думаю, что вышеприведенное блокирует первый splice_all
, когда файл достаточно большой из-за заполнения канала (?), Поэтому у меня также есть версия кода, которая fork
s для чтения и записи из канала одновременно, но он имеет ту же ошибку, что и эта версия, и его труднее читать.
РЕДАКТИРОВАТЬ: Моя версия ядра 2.6.22.18-co-0.7.3 (работает на coLinux в XP.)