Piszę mały program dla zabawy, który przenosi pliki przez TCP w C na Linux. Program odczytuje plik z gniazda i zapisuje go do pliku (lub odwrotnie). Początkowo używałem odczytu/zapisu i program działał poprawnie, ale potem dowiedziałem się o splice i chciałem spróbować.Czy splice Linux (2) działają podczas łączenia z gniazda TCP?
Kod, który napisałem ze splice działa doskonale podczas odczytu ze stdin (przekierowanego pliku) i zapisywania do gniazda TCP, ale natychmiast kończy się niepowodzeniem z ustawieniem zmiennej errno na EINVAL podczas odczytu z gniazda i zapisania na standardowe wyjście. Strona man stwierdza, że EINVAL jest ustawiony, gdy żaden deskryptor nie jest potokiem (nie jest to przypadek), offset jest przekazywany dla strumienia, który nie może szukać (nie ma przesunięć) lub system plików nie obsługuje łączenia, co prowadzi do na moje pytanie: czy to oznacza, że TCP może splajtować z rurą, ale nie na?
Załączam poniższy kod (bez kodu obsługi błędów) w nadziei, że właśnie zrobiłem coś złego. Opiera się głównie na Wikipedia example for splice.
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);
}
Na marginesie, myślę, że powyższe będzie blokował na pierwszym splice_all
gdy plik jest na tyle duża, ze względu na wypełnienie rury się (?), Więc mam również wersję kodu, który fork
s do odczytu i zapisu z potoku w tym samym czasie, ale ma taki sam błąd jak ta wersja i jest trudniejszy do odczytania.
EDIT: Moja wersja jądra 2.6.22.18-ko-0.7.3 (coLinux działa na XP).
Z powodzeniem użyłem 'splice' w Haskell: http://stackoverflow.com/questions/10080670/using-gnu-linux-system-call-splice-for-zero-copy-socket-to-socket-data- transfe też :) –