Lakukan man 2 sendfile
. Anda hanya perlu membuka file sumber di klien dan file tujuan di server, lalu panggil sendfile dan kernel akan memotong dan memindahkan data.
Solusi paling portabel adalah dengan membaca file dalam potongan-potongan, lalu menulis data ke soket, dalam satu lingkaran (dan sebaliknya, saat menerima file). Anda mengalokasikan buffer, read
ke dalam buffer itu, dan write
dari buffer itu ke soket Anda (Anda juga bisa menggunakan send
dan recv
, yang merupakan cara menulis dan membaca data khusus soket). Garis besarnya akan terlihat seperti ini:
while (1) {
// Read data into buffer. We may not have enough to fill up buffer, so we
// store how many bytes were actually read in bytes_read.
int bytes_read = read(input_file, buffer, sizeof(buffer));
if (bytes_read == 0) // We're done reading from the file
break;
if (bytes_read < 0) {
// handle errors
}
// You need a loop for the write, because not all of the data may be written
// in one call; write will return how many bytes were written. p keeps
// track of where in the buffer we are, while we decrement bytes_read
// to keep track of how many bytes are left to write.
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(output_socket, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
Pastikan untuk membaca dokumentasi untuk read
dan write
hati-hati, terutama saat menangani kesalahan. Beberapa kode kesalahan berarti Anda harus mencoba lagi, misalnya mengulang lagi dengan continue
pernyataan, sementara yang lain berarti ada sesuatu yang rusak dan Anda harus berhenti.
Untuk mengirim file ke soket, ada panggilan sistem, sendfile
itu hanya apa yang Anda inginkan. Ini memberi tahu kernel untuk mengirim file dari satu deskriptor file ke yang lain, dan kemudian kernel dapat menangani sisanya. Ada peringatan bahwa deskriptor file sumber harus mendukung mmap
(seperti, jadilah file sebenarnya, bukan soket), dan tujuannya harus berupa soket (sehingga Anda tidak dapat menggunakannya untuk menyalin file, atau mengirim data langsung dari satu soket ke soket lainnya); itu dirancang untuk mendukung penggunaan yang Anda gambarkan, mengirim file ke soket. Namun, itu tidak membantu menerima file; Anda perlu melakukan loop sendiri untuk itu. Saya tidak dapat memberi tahu Anda mengapa ada sendfile
panggilan tetapi tidak ada analog recvfile
.
Berhati-hatilah dengan sendfile
itu apakah Linux spesifik; itu tidak portabel untuk sistem lain. Sistem lain seringkali memiliki versi sendfile
mereka sendiri , tetapi antarmuka persisnya mungkin berbeda (FreeBSD, Mac OS X, Solaris).
Di Linux 2.6.17, splice
panggilan sistem diperkenalkan, dan mulai 2.6.23 digunakan secara internal untuk mengimplementasikan sendfile
. splice
adalah API tujuan yang lebih umum daripada sendfile
. Untuk deskripsi yang baik tentang splice
dan tee
, lihat penjelasan yang lumayan bagus dari Linus sendiri. Dia menunjukkan bagaimana menggunakan splice
pada dasarnya seperti loop di atas, menggunakan read
dan write
, kecuali buffer ada di kernel, sehingga data tidak harus ditransfer antara kernel dan ruang pengguna, atau bahkan mungkin tidak pernah melewati CPU (dikenal sebagai "zero-copy I/O").