Отправьте и Получите файл в программировании сокета в Linux с C/C++ (GCC/G ++)

Я хотел бы реализовать клиент-серверную архитектуру, работающую на Linux с помощью сокетов и языка C/C++, который способен к отправке и получению файлов. Есть ли какая-либо библиотека, которая делает эту задачу легкой? Кто-либо мог обеспечить пример?

37
задан Azendale 4 March 2016 в 03:20
поделиться

3 ответа

Самое портативное решение - это просто прочитать файл в кусках, а затем записать данные в сокет, по циклу (и так же наоборот, при получении файла). Вы выделяете буфер, читаете в этот буфер, и записываете из этого буфера в свой сокет (вы также можете использовать 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, за исключением того, что буфер находится в ядре, так что данные не должны передаваться между ядром и пользовательским пространством, или даже не могут когда-либо проходить через процессор (известный как "нулевая копия ввода/вывода").

66
ответ дан 27 November 2019 в 04:15
поделиться

Do aman 2 sendfile. Вам нужно только открыть исходный файл на клиенте и целевой файл на сервере, затем вызвать sendfile и ядро вырежет и переместит данные.

17
ответ дан 27 November 2019 в 04:15
поделиться

Этот файл послужит вам хорошим примером файла отправки : http://tldp.org/LDP/LGNET/91/misc/tranter/server. c.txt

8
ответ дан 27 November 2019 в 04:15
поделиться