Я хотел бы реализовать клиент-серверную архитектуру, работающую на Linux с помощью сокетов и языка C/C++, который способен к отправке и получению файлов. Есть ли какая-либо библиотека, которая делает эту задачу легкой? Кто-либо мог обеспечить пример?
Самое портативное решение - это просто прочитать файл в кусках, а затем записать данные в сокет, по циклу (и так же наоборот, при получении файла). Вы выделяете буфер, читаете
в этот буфер, и записываете
из этого буфера в свой сокет (вы также можете использовать send
и recv
, которые являются специфическими для сокета способами записи и чтения данных). Контур выглядел бы примерно так:
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;
}
}
Убедитесь, что внимательно прочитали документацию к прочтению
и записи
, особенно при работе с ошибками. Некоторые коды ошибок означают, что вы должны просто попробовать еще раз, например, просто повторить операцию continue
, в то время как другие означают, что что-то сломано, и вы должны остановиться.
Для отправки файла в сокет есть системный вызов, sendfile
, который делает именно то, что вы хотите. Он говорит ядру послать файл из одного дескриптора в другой, а затем ядро может позаботиться об остальном. Существует оговорка, что дескриптор файла-источника должен поддерживать mmap
(т.е. быть настоящим файлом, а не сокетом), а назначение должно быть сокетом (поэтому вы не можете использовать его для копирования файлов или отправки данных напрямую с одного сокета на другой); он предназначен для поддержки описываемого вами использования отправки файла на сокете. Однако, это не помогает при получении файла; для этого вам нужно будет выполнить цикл самостоятельно. Я не могу сказать, почему существует вызов sendfile
, но нет аналогичного recvfile
.
Остерегайтесь, что sendfile
специфичен для Linux; он не переносится на другие системы. Другие системы часто имеют собственные версии sendfile
, но точный интерфейс может отличаться (FreeBSD, Mac OS X, Solaris).
В Linux 2.6.17 системный вызов splice
был введен, а начиная с 2.6.23 для реализации sendfile
используется . splice
является более универсальным API, чем sendfile
. Для хорошего описания splice
и tee
смотрите довольно хорошее объяснение от самого Линуса. Он указывает на то, что использование splice
в основном похоже на описанный выше цикл, используя read
и write
, за исключением того, что буфер находится в ядре, так что данные не должны передаваться между ядром и пользовательским пространством, или даже не могут когда-либо проходить через процессор (известный как "нулевая копия ввода/вывода").
Do aman 2 sendfile
. Вам нужно только открыть исходный файл на клиенте и целевой файл на сервере, затем вызвать sendfile и ядро вырежет и переместит данные.
Этот файл послужит вам хорошим примером файла отправки
: http://tldp.org/LDP/LGNET/91/misc/tranter/server. c.txt