Re: epoll и reassembled TCP segments
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.04.15 17:36
Оценка: +2
Здравствуйте, lnkuser, Вы писали:

L>Тестил в Firefox, все отлично, запустил на Webkit-подобном движке и...

L>Обнаружил что tcp пакет с хедером и контент с json идут в разных tcp пакетах! (суммарный размер прмиерно 300 байт и оно почему -то разбивает на 2 пакета!)
L>В Firefox, опять таки, такого нет. Один пакет.

Любая программа, работающая с TCP, должна быть готова к тому, что данные могут прийти произвольно нарезанными порциями.

Соответственно, если пришел только хидер, то надо быть готовым дочитать данные, которые могут прийти позже. Кстати, и хидер может приехать частями, и данные тоже.
Re: epoll и reassembled TCP segments
От: landerhigh Пират  
Дата: 18.04.15 20:46
Оценка: +2
Здравствуйте, lnkuser, Вы писали:

L>Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...


рыть в сторону boost::asio, а то и вообще какого встраиваемого http сервера. Использовать сырые сокеты для такой задачи просто не следует.

L>Мой код с epoll просыпается когда есть данные на сокете, но считывается только хедер без данных...


Данные могут приезжать кусками какой угодно длины, и код должен быть к этому готов.
Re[3]: epoll и reassembled TCP segments
От: Слава  
Дата: 19.04.15 07:05
Оценка: +2
Здравствуйте, netch80, Вы писали:

N>Это как раз вряд ли. С минимальным IP4 MTU, равным 68 байт, минимум порции данных TCP на реальных стеках — 16 байт. Так что 300 байт нарежется на 19 порций.


Я про теорию. Сказано же в писании, что tcp есть поток, стало быть не следует от него ожидать каких-то границ пакетов. Это вообще надо в FAQ раздела вывесить.

N>Но в живом мире на Ethernet MTU менее 1300 не встречается.


Существует еще связь по GPRS и тому подобным каналам.
Отредактировано 19.04.2015 7:07 Слава . Предыдущая версия .
Re[4]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.04.15 07:47
Оценка: 8 (1)
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, netch80, Вы писали:


N>>Это как раз вряд ли. С минимальным IP4 MTU, равным 68 байт, минимум порции данных TCP на реальных стеках — 16 байт. Так что 300 байт нарежется на 19 порций.


С>Я про теорию. Сказано же в писании, что tcp есть поток, стало быть не следует от него ожидать каких-то границ пакетов. Это вообще надо в FAQ раздела вывесить.


С этим полностью согласен. Но примеры для объяснения должны быть реальными. А особенно — должно быть сказано, что это как раз тот случай, когда банально пройти через сито собственных функциональных тестов, но нарваться на проблему в реальном мире.
А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".

N>>Но в живом мире на Ethernet MTU менее 1300 не встречается.


С>Существует еще связь по GPRS и тому подобным каналам.


GPRS даёт обычно цифры типа 1400.
The God is real, unless declared integer.
epoll и reassembled TCP segments
От: lnkuser  
Дата: 18.04.15 17:31
Оценка:
Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...

Пишу простенький веб-сервер сугубо для своих нужно, нужно отправлять и получать JSON.

Тестил в Firefox, все отлично, запустил на Webkit-подобном движке и...
Обнаружил что tcp пакет с хедером и контент с json идут в разных tcp пакетах! (суммарный размер прмиерно 300 байт и оно почему -то разбивает на 2 пакета!)
В Firefox, опять таки, такого нет. Один пакет.



Мой код с epoll просыпается когда есть данные на сокете, но считывается только хедер без данных...

Код работы с epoll в целом стандартный:

    constexpr uint16_t EPOLL_SIZE {1024};

    static struct epoll_event events[EPOLL_SIZE];
    int sockfd {0};
    int epoll_events_count {0};

    struct sockaddr_in client_addr;
    socklen_t socklen = sizeof(struct sockaddr_in);

    epfd_ = epoll_create(EPOLL_SIZE);
    ev_.data.fd = sockfd_;
    ev_.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
    epoll_ctl(epfd_, EPOLL_CTL_ADD, sockfd_, &ev_);

    while (true) {
        try {
            process_loop();

            unsigned int timeout = process_get_standby();

            epoll_events_count = epoll_wait(epfd_, events, EPOLL_SIZE, timeout);
            for (int n=0; n<epoll_events_count; n++) {

                int fd = events[n].data.fd;
                if (fd == sockfd_) {
                    sockfd = accept(sockfd_, (struct sockaddr *)&client_addr, &socklen);
                    if (sockfd < 0)
                        continue;

                    //tcout() << "[info] established connection from: " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << ", socket: " << sockfd << std::endl;

                    uint32_t ip = ntohl(client_addr.sin_addr.s_addr);
                    uint16_t port = ntohs(client_addr.sin_port);

                    process_client_connect(sockfd, ip, port);
                }
                else {
                    if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP)) {
                        process_client_disconnect(fd);
                        continue;
                    }
                    else if (events[n].events & EPOLLIN || EPOLLPRI) {
                        process_data_received(fd);
                    }
                }
            }
        }
        catch (std::exception &e) {
            *lgr << LogLevel::error << "[exception] in server class: " << e.what();
        }
        catch (...) {
            *lgr << LogLevel::error << "[exception] in server class";
        }
    }


Код считывания с сокета, на котором есть данные:
нижеприведенный код создает буффер определенного размера, если считаны данный длинной с буффер — расширяем его еще и так пока считается меньше чем шаг буффера, потом ресайзим буффер

    int32_t rv {0};
    static constexpr uint32_t incoming_buffer_size {2048};
    try {
        buffer.clear();
        do {
            uint32_t current_position = buffer.size();
            buffer.resize(buffer.size() + incoming_buffer_size);
            rv = read(sockfd, buffer.data() + current_position, incoming_buffer_size);
            *lgr << LogLevel::info << __func__ << " rv " << rv;
            if (rv < 0) {
                *lgr << LogLevel::error << __func__ <<  "() broken connection detected during read";
                throw std::exception();
            }
            if ((rv < static_cast<int32_t>(incoming_buffer_size)) and (buffer.size() == incoming_buffer_size))
                buffer.resize(rv);
            else if (rv < static_cast<int32_t>(incoming_buffer_size))
                buffer.resize(current_position + rv);
        }
        while (rv == static_cast<int32_t>(incoming_buffer_size));
    }
    catch (...) {
        *lgr << LogLevel::error << __func__ << " exception";
        return -1;
    }

    *lgr << LogLevel::info << __func__ << " buffer.size() " << buffer.size();
    return buffer.size();



опция TCP_DEFER_ACCEPT не помогает, может она не для этого предназначена? вроде как должна

Тоесть мой код видит первый пакет и все, второй не видит. Wireshark говорит что пакет доставлен.


Запустил пример на асинхронном boost, тоже самое...

Подскажите пожалуйста
Re[2]: epoll и reassembled TCP segments
От: lnkuser  
Дата: 18.04.15 17:40
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, lnkuser, Вы писали:


L>>Тестил в Firefox, все отлично, запустил на Webkit-подобном движке и...

L>>Обнаружил что tcp пакет с хедером и контент с json идут в разных tcp пакетах! (суммарный размер прмиерно 300 байт и оно почему -то разбивает на 2 пакета!)
L>>В Firefox, опять таки, такого нет. Один пакет.

Pzz>Любая программа, работающая с TCP, должна быть готова к тому, что данные могут прийти произвольно нарезанными порциями.


Pzz>Соответственно, если пришел только хидер, то надо быть готовым дочитать данные, которые могут прийти позже. Кстати, и хидер может приехать частями, и данные тоже.



Прикол в том, что после считывания первого пакета на сокете пусто, повторный read будет блокирующим.

Можно ли как-то принудительно ждать, пока сегменты соберуться? Ничего путного в поиске я не нашел...
Re[3]: epoll и reassembled TCP segments
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.04.15 17:46
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Прикол в том, что после считывания первого пакета на сокете пусто, повторный read будет блокирующим.


Ну да. Если два куска шли физически отдельными пакетами, между их появлением будет некоторая пауза.

L>Можно ли как-то принудительно ждать, пока сегменты соберуться? Ничего путного в поиске я не нашел...


Нет, нельзя.

А откуда TCP вообще может знать, что "сегменты собрались". Ему на стороне отправителя сказали два раза send(). Откуда он знает, что это связанные данные?
Re[3]: epoll и reassembled TCP segments
От: alex19  
Дата: 19.04.15 00:32
Оценка:
> повторный read будет блокирующим.

Только если сокет блокирующий

$ man read
...
ERRORS
EAGAIN The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read
would block.

EAGAIN or EWOULDBLOCK
The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.
POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same
value, so a portable application should check for both possibilities.
Re: epoll и reassembled TCP segments
От: alex19  
Дата: 19.04.15 00:40
Оценка:
> Обнаружил что tcp пакет с хедером и контент с json идут в разных tcp пакетах!

Данные пришедшие по tcp складываются в буфер, из которого вы читаете. OS не делает разделения по границам пришедших пакетов. Т.е. данные туда могли прийти хоть по одному байту, OS отдаст вам сколько вы запросили (все пришедшие пакеты) или меньше (по одному байту, хотя пакет был на 1К), если по какой-то причине не успеет отдать все (прерывание сигналом, например). Уверен, что если вы почитаете документацию, то самостоятельно сможете написать программу, которая будет передавать данные в пакетах с полезной нагрузкой по одному байту...

Я это все к тому, что независимо от размера передаваемых данных они не факт, что придут в одном пакете и даже если в одном, то не факт, что вы их все получите за одни read, более того, размер read может быть как больше, так и меньше размера передаваемого по сети пакета.
Re[4]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.04.15 05:59
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>А откуда TCP вообще может знать, что "сегменты собрались". Ему на стороне отправителя сказали два раза send(). Откуда он знает, что это связанные данные?


Ну по спецификации TCP такое возможно (флаг PSH):

[quote]
Sometimes users need to be sure that all the data they have
submitted to the TCP has been transmitted. For this purpose a push
function is defined. To assure that data submitted to a TCP is
actually transmitted the sending user indicates that it should be
pushed through to the receiving user. A push causes the TCPs to
promptly forward and deliver data up to that point to the receiver.
The exact push point might not be visible to the receiving user and
the push function does not supply a record boundary marker.
[/quote]

то есть присылка без PSH может не вызывать немедленной готовности данных, а вызовет или по пакету с PSH, или по таймауту, или по существенному заполнению буфера.

Но на это все забили на практике ещё до 90-го...
The God is real, unless declared integer.
Re: epoll и reassembled TCP segments
От: Слава  
Дата: 19.04.15 06:19
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...


Пакет от отправителя в 300 байт размером, вам может придти в виде 300 пактов по 1 байту. Собирайте у себя.
Re[2]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.04.15 06:27
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, lnkuser, Вы писали:


L>>Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...


С>Пакет от отправителя в 300 байт размером, вам может придти в виде 300 пактов по 1 байту. Собирайте у себя.


Это как раз вряд ли. С минимальным IP4 MTU, равным 68 байт, минимум порции данных TCP на реальных стеках — 16 байт. Так что 300 байт нарежется на 19 порций. Но в живом мире на Ethernet MTU менее 1300 не встречается.
The God is real, unless declared integer.
Re[5]: epoll и reassembled TCP segments
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 19.04.15 08:12
Оценка:
Здравствуйте, netch80, Вы писали:

N>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


А он разве где-то за пределами UNIX-ов поддерживается? Насколько знаю, ни в OS X ни в Windows нет поддержки. Да и не без своих проблем, вроде как. Но в целом, идея безусловно здравая, не надо придумывать новый протокол, если можно обойтись существующими.
Re[6]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.04.15 08:39
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>Здравствуйте, netch80, Вы писали:


N>>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


KP>А он разве где-то за пределами UNIX-ов поддерживается? Насколько знаю, ни в OS X ни в Windows нет поддержки.


OS X это Unix, конкретно, в основном BSD.
Для Windows есть минимум 2 доступные бесплатные реализации и несколько платных.
The God is real, unless declared integer.
Re: epoll и reassembled TCP segments
От: smeeld  
Дата: 19.04.15 09:13
Оценка:
Здравствуйте, lnkuser, Вы писали:


L>Мой код с epoll просыпается когда есть данные на сокете, но считывается только хедер без данных


Считывайте с сокета по мере прихода пакетов. Сделать сокеты неблокирующими, буфер для чтения фиксированным.
Количество данных для чтения в recv/read/recvmsg назначаем равным размеру фиксированного
буфера. Если чтение вернуло -1, и error выставился в EAGAIN, ждём пакетов на сокете, которые, когда придут,
просигнализируют о себе появлением в возврате из epoll_wait. Если прочитали размер фиксированного буфера, значит
на сокете, возможно, есть непрочитанные данные, после обработки прочитанных данных нужно будет вызвать read/recv/recvmsg
снова. Если чтение вернуло количество, меньшее запрошенного, то на сокете данных больше нет, ждём дальше, если в прочитанных
данных только хедер без тела, например. Разные буфера-куски фиксированного размера, прочитаные в разное время, можно собирать в
распределёный буфер-список буферов фиксированного размера, представляющий собой абстракцию непрерывного буфера. Хотя в Вашем
resize, может, именно это. Такими являются буфера приёмных и отправных пакетов в ядрах ОС.
Re[7]: epoll и reassembled TCP segments
От: smeeld  
Дата: 19.04.15 09:40
Оценка:
Здравствуйте, netch80, Вы писали:

N>OS X это Unix, конкретно, в основном BSD.


Это не Unix, как и BSD. Это Unix-like.
Re[7]: epoll и reassembled TCP segments
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 19.04.15 09:45
Оценка:
Здравствуйте, netch80, Вы писали:

N>OS X это Unix, конкретно, в основном BSD.


ПОловина BSD, половина Mach. Сеть – старая BSD с сильными изменениями.

N>Для Windows есть минимум 2 доступные бесплатные реализации и несколько платных.


Которые нужно еще отдельно установить. Однозначно не вариант, если приложение не для гиков, конечно.
Re[5]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 20.04.15 08:32
Оценка:
Здравствуйте, netch80, Вы писали:

N>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


Я бы этого точно этого не рекомендовал. Это противоречит KISS. TCP элементарен в использовании. Чтобы использовать расширенные возможности SCTP нужно разобраться с кучей доков, а в конце выясняется, что всех удовольствий — это возможность указать системе границы пакетов которые нужно отдавать пользователю. Вся остальная дребедень типа мультихома нужна только в специфических случаях и требует ещё кучу сложностей.

Так что начинать стоит с TCP, и обращаться к другим вариантам только если через TCP ну никак не выходит.

В данном же случае, HTTP вообще не предполагает пакетных границ. Он уже заточен под использование TCP. Так что ожидание данных в рамках одного пакета — это классические грабли всех начинающих сетевых программистов. Нужно изначально проектировать решение как систему обработчиков событий. Нашёл в буфере ASCII 10, передай управление обработчику строк. Обработчик обнаружил хидер дающий длину тела, пусть запустит ожидание нужного количество байт тела и так далее. Наличие epoll вообще не играет особой роли. Лучше вообще от него абстрагироваться, использовав какой-нибудь libevent или собственную библиотеку. Есть даже люди умудряющиеся читать-писать-обрабатывать в разных потоках. Только и в этом случае всё подчиняется тому же принципу обработки событий.
Re[5]: epoll и reassembled TCP segments
От: Mr.Delphist  
Дата: 21.04.15 12:20
Оценка:
Здравствуйте, netch80, Вы писали:

N>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


Хм, а что изменит SCTP? Ну, будет информация ходить через другой транспорт, и чего? Каких-то кардинальных упрощений в прикладном смысле это человеку не даст. Лучше тогда уж в самом деле всякий boost::asio, Protobuf и всё такое прочее.
Re[6]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 22.04.15 04:47
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, netch80, Вы писали:


N>>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


MD>Хм, а что изменит SCTP?


Границы сообщений, гарантированные транспортом.

MD> Ну, будет информация ходить через другой транспорт, и чего? Каких-то кардинальных упрощений в прикладном смысле это человеку не даст. Лучше тогда уж в самом деле всякий boost::asio, Protobuf и всё такое прочее.


Условие данного совета — собственный протокол. Что там внутри у этого протокола — вопрос следующий.
The God is real, unless declared integer.
Re[6]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 22.04.15 04:52
Оценка:
Здравствуйте, v_andal, Вы писали:

_>Здравствуйте, netch80, Вы писали:


N>>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


_>Я бы этого точно этого не рекомендовал. Это противоречит KISS. TCP элементарен в использовании.


Постоянная необходимость держать собственный буфер, двигаться по нему с байтовыми позициями (а не целыми сообщениями) и собирать сообщения из байтов это никак не "элементарен в использовании", это изуверски сложно для новичков и неудобно даже для профессионалов.

_> Чтобы использовать расширенные возможности SCTP нужно разобраться с кучей доков,


Вы обманно подменили тезис дискуссии. Я не говорил про "расширенные возможности SCTP".

_> а в конце выясняется, что всех удовольствий — это возможность указать системе границы пакетов которые нужно отдавать пользователю. Вся остальная дребедень типа мультихома нужна только в специфических случаях и требует ещё кучу сложностей.


Не используйте, и она ничего не будет требовать. Зато границы сообщений — архиполезно.

_>В данном же случае, HTTP вообще не предполагает пакетных границ. Он уже заточен под использование TCP.


Ещё один не прочитавший явно написанное русским по фоновому про "собственный протокол".

_> Так что ожидание данных в рамках одного пакета — это классические грабли всех начинающих сетевых программистов. Нужно изначально проектировать решение как систему обработчиков событий.


Не "нужно", а "неизбежно при использовании TCP".
The God is real, unless declared integer.
Re[7]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 22.04.15 10:39
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, v_andal, Вы писали:


_>>Здравствуйте, netch80, Вы писали:


N>>>А ещё я бы в тот же FAQ запихнул жёсткое "нужен собственный протокол — начинайте с SCTP и переходите на TCP только если первый недоступен".


_>>Я бы этого точно этого не рекомендовал. Это противоречит KISS. TCP элементарен в использовании.


N>Постоянная необходимость держать собственный буфер, двигаться по нему с байтовыми позициями (а не целыми сообщениями) и собирать сообщения из байтов это

никак не "элементарен в использовании", это изуверски сложно для новичков и неудобно даже для профессионалов.

Простите, однако SCTP также не гарантирует сохранение границ пакетов. Смотрите Секцию 10 в https://www.rfc-editor.org/rfc/rfc2960.txt протокол может делать частичную доставку пакета. Так что в любом случае приходится вести учёт полученных байтов и держать буфер. То бишь в простейшем варианте использования разницы никакой, только документация сложнее и системные вызовы более заморочные. На практике, границы пакета ничего не дают для программы.

_>> а в конце выясняется, что всех удовольствий — это возможность указать системе границы пакетов которые нужно отдавать пользователю. Вся остальная дребедень типа мультихома нужна только в специфических случаях и требует ещё кучу сложностей.


N>Не используйте, и она ничего не будет требовать. Зато границы сообщений — архиполезно.


Смотри выше. Эти границы — фикция.


_>>В данном же случае, HTTP вообще не предполагает пакетных границ. Он уже заточен под использование TCP.


N>Ещё один не прочитавший явно написанное русским по фоновому про "собственный протокол".


Извините, я просто перешёл от "собственный протокол" к "данному случаю HTTP протокола". Ничего больше.

_>> Так что ожидание данных в рамках одного пакета — это классические грабли всех начинающих сетевых программистов. Нужно изначально проектировать решение как систему обработчиков событий.


N>Не "нужно", а "неизбежно при использовании TCP".


То же самое относится к SCTP. Нужно обязательно проверять получил ли ты полный пакет, или же только partial delivery.
Re[8]: epoll и reassembled TCP segments
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 22.04.15 13:49
Оценка:
Здравствуйте, v_andal, Вы писали:

_>Простите, однако SCTP также не гарантирует сохранение границ пакетов. Смотрите Секцию 10 в https://www.rfc-editor.org/rfc/rfc2960.txt протокол может делать частичную доставку пакета. Так что в любом случае приходится вести учёт полученных байтов и держать буфер. То бишь в простейшем варианте использования разницы никакой, только документация сложнее и системные вызовы более заморочные. На практике, границы пакета ничего не дают для программы.

Боже мой! Нужно проверить один флажок и заполнять если он в 1 то ли дело TCP!
Sic luceat lux!
Re[8]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 22.04.15 19:26
Оценка:
Здравствуйте, v_andal, Вы писали:

_>Простите, однако SCTP также не гарантирует сохранение границ пакетов. Смотрите Секцию 10 в https://www.rfc-editor.org/rfc/rfc2960.txt протокол может делать частичную доставку пакета.


Это не есть несохранение границ. Границы при этом сохраняются без проблем: с помощью того же флага можно выяснять, идёт речь о новом сообщении или нет. Не происходит такого, что одним receive получаются фрагменты нескольких сообщений, и в этом главное и принципиальное преимущество по сравнению с TCP.
Более того, в практически встречаемых API, чтобы производилась такая частичная доставка, надо постараться. Вот, например, из мана sctp_recvmsg на FreeBSD:

The length of the message msg to be received is bounded by len. If the message is too long to fit in the users receive buffer, then the flags argument will not have the MSG_EOF flag applied. If the message is a complete message then the flags argument will have MSG_EOF set.


Большинство остальных реализаций следуют тому же принципу. В случае более простого вызова (recvmsg, recv, read) такой проблемы аналогично нет, если размер буфера заведомо достаточен для полного сообщения, но там может не оказаться диагностики дробления.

_> Так что в любом случае приходится вести учёт полученных байтов и держать буфер.


Нет, не приходится. Передавайте приёмный буфер нужного размера и забудьте о проблеме.

_> На практике, границы пакета ничего не дают для программы.


Вы о чём? Если о результатах своего прочтения, то они неадекватны текущей реальности. Если о практике с поправкой, то они чудовищно удобны.

N>>Не используйте, и она ничего не будет требовать. Зато границы сообщений — архиполезно.

_>Смотри выше. Эти границы — фикция.

Повторяю: Вы совершенно некорректно прочли RFC. Даже с учётом возможной частичной доставки таким образом, границы — ни капельки не фикция, потому что в результат одного RECEIVE не попадут части двух разных сообщений, а признак границы сообщения всё равно тривиально восстанавливается (!partial => последняя часть сообщения).

N>>Не "нужно", а "неизбежно при использовании TCP".

_>То же самое относится к SCTP. Нужно обязательно проверять получил ли ты полный пакет, или же только partial delivery.

Нет, не нужно, если буфер достаточен для приёма полного сообщения.
The God is real, unless declared integer.
Re[9]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 23.04.15 08:01
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Не "нужно", а "неизбежно при использовании TCP".

_>>То же самое относится к SCTP. Нужно обязательно проверять получил ли ты полный пакет, или же только partial delivery.

N>Нет, не нужно, если буфер достаточен для приёма полного сообщения.


Но с буфером-то всё равно придётся возится. Придётся "помнить", что этот буфер содержит только часть сообщения. Кроме того, редко когда приходящие пакеты имеют одинаковую длину, а значит ты не знаешь какой длины буфер тебе нужен.

Всё, что я пытаюсь сказать, знание границ пакета ничего не упрощает. Работа с буфером никуда не исчезает и проще она не становится. Алгоритм остаётся тем же: выделил некий буфер, прочёл, проверил сколько реально нужно памяти, если надо увеличил буфер и снова читаешь. Если протокол подразумевает пакеты, то в SCTP тебе сообщают длину пакета, в TCP нужно самому взять первые 2 или 4 байта, чтобы узнать длину пакета. Вся разница в 2-х строчках кода. И ради этого трахаться с более сложной документацией для SCTP?

Я уже 15 лет работаю с обоими этими протоколами, и не устаю восхищаться разработчиками TCP. С этим протоколом я будучи полным нубом разобрался за пару дней. На штудирование SCTP ушла неделя, и я до сих пор регулярно заглядываю в доки проверяя, все ли детали я учёл.

Да и давайте уж смотреть на вещи реально. Если считать работу с буфером "архисложной", то тогда что говорить о работе с таймерами, об обработке сетевых ошибок, да и об обработке полученных данных? Работа с буфером укладывается в 150-200 строк С-кода, на фоне остального кода это тривиальный мизер. Я еще в первые месяцы написания сетевых программ сляпал себе крошечный модуль-администратор для буфера и с тех пор не думаю об этом. Этот модуль я пользую и для TCP и для SCTP.
Re[10]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.15 09:56
Оценка:
Здравствуйте, v_andal, Вы писали:

N>>>>Не "нужно", а "неизбежно при использовании TCP".

_>>>То же самое относится к SCTP. Нужно обязательно проверять получил ли ты полный пакет, или же только partial delivery.
N>>Нет, не нужно, если буфер достаточен для приёма полного сообщения.
_>Но с буфером-то всё равно придётся возится. Придётся "помнить", что этот буфер содержит только часть сообщения. Кроме того, редко когда приходящие пакеты имеют одинаковую длину, а значит ты не знаешь какой длины буфер тебе нужен.

Во многих случаях я это гарантированно знаю за счёт ограничений протокола. И всё равно важнее то, что каждый возврат из recv*() для SCTP содержит части не более одного сообщения.

_>Всё, что я пытаюсь сказать, знание границ пакета ничего не упрощает. Работа с буфером никуда не исчезает и проще она не становится.


Она реально становится проще. Даже в случае непредсказуемого размера сообщений, и особенно — если буфера достаточно.

_> Алгоритм остаётся тем же: выделил некий буфер, прочёл, проверил сколько реально нужно памяти, если надо увеличил буфер и снова читаешь. Если протокол подразумевает пакеты, то в SCTP тебе сообщают длину пакета, в TCP нужно самому взять первые 2 или 4 байта, чтобы узнать длину пакета. Вся разница в 2-х строчках кода. И ради этого трахаться с более сложной документацией для SCTP?


Там не из-за чего "трахаться", для данного уровня всё элементарно.

_>Я уже 15 лет работаю с обоими этими протоколами, и не устаю восхищаться разработчиками TCP. С этим протоколом я будучи полным нубом разобрался за пару дней. На штудирование SCTP ушла неделя, и я до сих пор регулярно заглядываю в доки проверяя, все ли детали я учёл.


Когда используете более сложные особенности — да. Когда используете его на уровне TCP с границами сообщений — не о чем заглядывать.
Восхищаться разработчиками TCP можно — до определённого предела, пока не понимаешь, что мириады индусов всех национальностей не умеют и не будут уметь работать с ним.

_>Да и давайте уж смотреть на вещи реально. Если считать работу с буфером "архисложной", то тогда что говорить о работе с таймерами, об обработке сетевых ошибок, да и об обработке полученных данных? Работа с буфером укладывается в 150-200 строк С-кода, на фоне остального кода это тривиальный мизер.


Это тривиальный мизер, когда вы знаете об этом. А когда кодер об этом не знает — он просто игнорирует проблему.
Я видел много протоколов, где в принципе не предусмотрены границы сообщений, и надо или гарантировать не более одного сообщения за итерацию с каждой стороны, или применять тяжёлые формы неестественного интеллекта для поиска границ.
Например, я сейчас работаю с FIX. Гарантия правильного опознания границ для всех случаев — может быть только при грамматическом разборе потока при условии словаря всех атрибутов. Реально 90% применяющих плевали на это и детектируют самым тупым образом.

_> Я еще в первые месяцы написания сетевых программ сляпал себе крошечный модуль-администратор для буфера и с тех пор не думаю об этом. Этот модуль я пользую и для TCP и для SCTP.


Одинаковым кодом? Звучит крайне подозрительно.
The God is real, unless declared integer.
Re[11]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 23.04.15 12:22
Оценка:
Здравствуйте, netch80, Вы писали:


N>Во многих случаях я это гарантированно знаю за счёт ограничений протокола. И всё равно важнее то, что каждый возврат из recv*() для SCTP содержит части не более одного сообщения.


И чем же это важно? Это однозначно плохо для пропускной способности протокола. Каждый системный вызов дорого обходится. Я так наоборот делаю всё возможное, чтобы за один системный вызов вытащить как можно больше данных. Просто с меня требуют максимальную пропускную способность. Опять же, с точки зрения обработки данных абсолютно без разницы сколько у тебя пакетов в буфере. Алгоритм остаётся прежним "пакет в начале буфера, обработай, удали обработанное, смести начало буфера, у тебя опять пакет в начале буфера".

_>>Всё, что я пытаюсь сказать, знание границ пакета ничего не упрощает. Работа с буфером никуда не исчезает и проще она не становится.


N>Она реально становится проще. Даже в случае непредсказуемого размера сообщений, и особенно — если буфера достаточно.


Ну да, если ты веришь, что буфера достаточно, то значит ты создаёшь потенциальную дыру. Писать всё равно приходится исходя из положения, что буфера недостаточно. Из практического опыта, если не использовать спец-свойства SCTP типа мультихома, то код для TCP мало отличается от кода для SCTP.

_>> Алгоритм остаётся тем же: выделил некий буфер, прочёл, проверил сколько реально нужно памяти, если надо увеличил буфер и снова читаешь. Если протокол подразумевает пакеты, то в SCTP тебе сообщают длину пакета, в TCP нужно самому взять первые 2 или 4 байта, чтобы узнать длину пакета. Вся разница в 2-х строчках кода. И ради этого трахаться с более сложной документацией для SCTP?


N>Там не из-за чего "трахаться", для данного уровня всё элементарно.


Для начала нужно разобраться со всем многообразием уровней предлагаемых SCTP и понять, какой же уровень "данный". Собственно ничего другого я не имею в виду. Разобравшись с доками действительно выясняется, что SCTP можно использовать точно также как TCP

N>Восхищаться разработчиками TCP можно — до определённого предела, пока не понимаешь, что мириады индусов всех национальностей не умеют и не будут уметь работать с ним.


Ну так с уверенностью можно сказать, что эти самые мириады не будут уметь работать и с SCTP. С другой стороны, имеется куча народа умеющих работать с TCP, количество же людей умеющих пользовать SCTP гораздо скромнее. Да и сам протокол используется только в узкоспециализированных местах. Не идёт он в массы


N>Это тривиальный мизер, когда вы знаете об этом. А когда кодер об этом не знает — он просто игнорирует проблему.


Эти слова не привязаны к TCP протоколу. Можно сказать, что знания о partial read в SCTP этот тривиальный мизер, который кодер просто игнорирует, надеясь, что его буфер всегда достаточного размера и он всегда получит полную запись. А в результате все получают очередной говнокод.

N>Я видел много протоколов, где в принципе не предусмотрены границы сообщений, и надо или гарантировать не более одного сообщения за итерацию с каждой стороны, или применять тяжёлые формы неестественного интеллекта для поиска границ.


А какое это имеет отношение к дискуссии о преимуществах SCTP по отношению к TCP? Дурацкий протокол можно придумать вне зависимости от используемого транспорта. С другой стороны, очень часто требования предъявляемые к протоколу не дают возможности задавать чёткие границы для пакетов. Тот же HTTP протокол используется в ситуациях, когда ответ может генериться кусками и куски могут быть слишком большими для буферизации. Так что чётких границ тут не задашь. Опять же, наличие чётких границ не даёт гарантии, что протокол хороший. SMPP протокол даёт чёткие границы пакетов (хоть и работает над TCP), но в пределах этих границ делает много глупостей, делающих работу с этим протоколом заморочной.


_>> Я еще в первые месяцы написания сетевых программ сляпал себе крошечный модуль-администратор для буфера и с тех пор не думаю об этом. Этот модуль я пользую и для TCP и для SCTP.


N>Одинаковым кодом? Звучит крайне подозрительно.


Хм. Под "администрированием буфера" я понимаю "выделить место для стольких то байт", "отметить такое-то количество байт как данные", "убрать такое-то количество данных в начале", "убрать такое-то количество данных с конца", "дать доступ к данным в начале буфера". Эти операции остаются одинаковыми для обоих протоколов.
Re[11]: epoll и reassembled TCP segments
От: Слава  
Дата: 23.04.15 12:46
Оценка:
Здравствуйте, netch80, Вы писали:

N>SCTP.


Когда этот протокол появится в стандартной поставке какой-нибудь Windows 14, когда он же появится в мобильных платформах — массово, тогда и можно будет его использовать.

Иначе это получится программа для общения между двумя линуксами, причем оба линукса должны контролироваться автором программы — чтобы там SCTP заработал. Не у всех такие задачи.
Re[12]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.15 13:24
Оценка:
Здравствуйте, Слава, Вы писали:

N>>SCTP.


С>Когда этот протокол появится в стандартной поставке какой-нибудь Windows 14, когда он же появится в мобильных платформах — массово, тогда и можно будет его использовать.


В линуксах он уже много лет из коробки => есть в андроиде. (Хотя не знаю насчёт его явовского API.)
В BSD тоже много лет из коробки => скорее всего, есть в iOS на тех же условиях.
Для винды есть реализации, включая бесплатные, но для меня лично это как проблемы индейцев — она мне не платформа.

С>Иначе это получится программа для общения между двумя линуксами, причем оба линукса должны контролироваться автором программы — чтобы там SCTP заработал.


Для этого много лет не нужно никаких усилий, просто запускаешь и работает.

С> Не у всех такие задачи.


Согласен. Случай он разный бывает. В одной подопечной железяке мозгов даже на TCP не хватает, остаётся UDP.
The God is real, unless declared integer.
Re[12]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 24.04.15 06:09
Оценка:
Здравствуйте, v_andal, Вы писали:

_>И чем же это важно? Это однозначно плохо для пропускной способности протокола. Каждый системный вызов дорого обходится. Я так наоборот делаю всё возможное, чтобы за один системный вызов вытащить как можно больше данных. Просто с меня требуют максимальную пропускную способность.


Твоя позиция и ваша специфика понятны, но ты зациклился на ней и упорно не хочешь вникнуть в то, что я говорю.
Я несколько раз (два — сам, ещё пару — через ближайших коллег, и слышал ещё) сталкивался со следующей ситуацией. Есть какая-то самопальная железка или прошивка к чему-то IPMI-BMC-подобному, в которую года 3 назад из-за улучшения аппаратных возможностей впихнули Linux, обрадовались облегчению, уволили всех толковых и посадили толпу выпускников заборостроительного ПТУ. Железка регулярно посылает данные мониторинга (телеметрию, whatever). Её можно отправлять по UDP, тогда проблем с границами нет, но есть шанс потерь. Кто-то из среднего начальства взвивается и говорит "потерь быть не должно", люди переключаются на TCP, и тут оказывается, что автор отправляющего агента Кришназевул Абдулкумар (иногда его зовут Ху Ли) искренне считает, что что одним send() отправлено, то одним recv() и получится, и никакой маркировки длины или эскейпинга не придумывает (каждый байт у него на строжайшем учёте, за лишний байт бьют по рукам и изгоняют в дерёвню, формат запутан и недиагностируем). Всё работает в его лаборатории на коленке, а когда начинаются проблемы с реальной загрузкой приложения и сети, он и его начальство (у которого мозгов ещё меньше, но больше наглости и изворотливости) посылают ко всем индийским лешим, утверждая, что проблемы не его стороне. Прочитать, что TCP отдаст за один recv() два пакета, и понять границы после этого невозможно, уже не укладывается в его квадратно-гнездовую башку. Вопрос не в максимальной производительности или количестве данных за один вызов, это не стоит проблемой — внутренняя обработка значительно сложнее сисколла. Вопрос в корректности передачи и разбора.
Вот именно поэтому я говорю, что из-за таких проблем надо в качестве подложки по умолчанию считать SCTP, а TCP применять только в трёх случаях — или неустранимое наследство, или требуется максимальная производительность на относительно мелких порциях, или поток вообще не ложится в концепцию сообщений крупнее октета (вряд ли это относится к чему-то более новому, чем telnet или ftp data).

(К тому же для задачи типа телеметрии или мультимедиа SCTP вкусен ещё возможностью сочетать настойчивость в доставке сообщения с ограничением количества попыток или времени этих попыток — что в принципе невозможно по TCP без разрыва соединения и требует написания собственной подложки для ретрансмитов в случае UDP.)

Ты можешь сказать, что я преувеличиваю долю таких случаев, что такие задачи, о которых я говорю, занимают жалкие доли процента от всего трафика. И я с этим соглашусь. Но именно от количества случаев, когда надо сочинять свой протокол поверх предоставляемого ОС транспорта, этих случаев очень много (и я всерьёз считаю, что их более половины). Это всё не относится к HTTP и прочим чудесам, занимающим 99% мирового трафика — это самопал, но это тема данного топика.

_> Алгоритм остаётся прежним "пакет в начале буфера, обработай, удали обработанное, смести начало буфера, у тебя опять пакет в начале буфера".


Фазы "смести начало буфера" в случае SCTP нет. "Удали обработанное" сводится к полной вычистке буфера. Так что тут реально проще. Но опять же дело не в этом. Я полностью согласен с тезисом, что при необходимости выжать максимум скорости получается множество слоёв сверху, по сравнению с которым работа с буфером — мелочь. Но см. выше про случаи из моего мира.

_>Ну да, если ты веришь, что буфера достаточно, то значит ты создаёшь потенциальную дыру. Писать всё равно приходится исходя из положения, что буфера недостаточно.


Я могу сделать так, что если после sctp_recvmsg() не вижу MSG_EOR, то соединение тупо рвётся сразу, и генерируется аларм "источник сошёл с ума". Для описанных применений это полностью адекватно.

N>>Там не из-за чего "трахаться", для данного уровня всё элементарно.

_>Для начала нужно разобраться со всем многообразием уровней предлагаемых SCTP и понять, какой же уровень "данный". Собственно ничего другого я не имею в виду. Разобравшись с доками действительно выясняется, что SCTP можно использовать точно также как TCP

Игнорируя поддержку границ? А зачем?

_>Ну так с уверенностью можно сказать, что эти самые мириады не будут уметь работать и с SCTP.


Будут уметь, просто потому, что они натренированы, как собачки, написать заданное в инструкции имя сисколла и подставить ему заданные параметры, и это будет работать. В случае же TCP им нужно скормить готовую библиотеку, которая будет держать буфер вызывать коллбэк при получении полного сообщения, написать её сами или догадаться, что её надо написать, они не могут.

_>Эти слова не привязаны к TCP протоколу. Можно сказать, что знания о partial read в SCTP этот тривиальный мизер, который кодер просто игнорирует, надеясь, что его буфер всегда достаточного размера и он всегда получит полную запись. А в результате все получают очередной говнокод.


См. выше про специфику таких случаев.

_>А какое это имеет отношение к дискуссии о преимуществах SCTP по отношению к TCP? Дурацкий протокол можно придумать вне зависимости от используемого транспорта. С другой стороны, очень часто требования предъявляемые к протоколу не дают возможности задавать чёткие границы для пакетов. Тот же HTTP протокол используется в ситуациях, когда ответ может генериться кусками и куски могут быть слишком большими для буферизации. Так что чётких границ тут не задашь. Опять же, наличие чётких границ не даёт гарантии, что протокол хороший. SMPP протокол даёт чёткие границы пакетов (хоть и работает над TCP), но в пределах этих границ делает много глупостей, делающих работу с этим протоколом заморочной.


Кто бы спорил. Я работал с SIP и FIX. Оба — ужас на крыльях ночи.

_>Хм. Под "администрированием буфера" я понимаю "выделить место для стольких то байт", "отметить такое-то количество байт как данные", "убрать такое-то количество данных в начале", "убрать такое-то количество данных с конца", "дать доступ к данным в начале буфера". Эти операции остаются одинаковыми для обоих протоколов.


Для SCTP, повторяю, тебе не нужны операции "убрать в начале" (а для обоих — "убрать с конца"). У тебя остаётся для приёмного буфера — очистить буфер, дописать в конец буфера, отдать буфер на рассмотрение. Для передающего — передать буфер целиком (добавить в конец списка), убрать переданный из начала списка. В случае действительно сложной политики стиля random early drop можно делать удаления из середины, в случае QoS — расставлять приоритеты, это будет общее с TCP, но это ты не описал.
The God is real, unless declared integer.
Re[13]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 24.04.15 07:29
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, v_andal, Вы писали:


N>Вот именно поэтому я говорю, что из-за таких проблем надо в качестве подложки по умолчанию считать SCTP, а TCP применять только в трёх случаях — или неустранимое наследство, или требуется максимальная производительность на относительно мелких порциях, или поток вообще не ложится в концепцию сообщений крупнее октета (вряд ли это относится к чему-то более новому, чем telnet или ftp data).


Боже мой. Да тупой индус программер наворочает дерьма для SCTP столько же, сколько он его льёт для TCP. Он просто вообще не сможет разобраться, как с ним работать. Утонет на фазе создания ассоциации. От глупости и незнания нельзя защититься более продвинутым протоколом. Поэтому, подобные аргументы в топку. Качественная программа не будет иметь значительных отличий.


N>(К тому же для задачи типа телеметрии или мультимедиа SCTP вкусен ещё возможностью сочетать настойчивость в доставке сообщения с ограничением количества попыток или времени этих попыток — что в принципе невозможно по TCP без разрыва соединения и требует написания собственной подложки для ретрансмитов в случае UDP.)


Для разных задач бывают нужны разные инструменты. Я не молюсь на TCP, я всего лишь считаю, что это очень хороший базовый протокол. Уходить от него стоит только в случаях не вписывающихся в "базу".

N>Фазы "смести начало буфера" в случае SCTP нет. "Удали обработанное" сводится к полной вычистке буфера. Так что тут реально проще. Но опять же дело не в этом. Я полностью согласен с тезисом, что при необходимости выжать максимум скорости получается множество слоёв сверху, по сравнению с которым работа с буфером — мелочь. Но см. выше про случаи из моего мира.


И эту разницу ты и считаешь "архисложной"? Только не надо меня опять отсылать к кодерам не знающим, что творят. Если для человека добавление одной-двух строчек кода — архисложно, то ему уже ничем не помочь. ИМХО


N>Будут уметь, просто потому, что они натренированы, как собачки, написать заданное в инструкции имя сисколла и подставить ему заданные параметры, и это будет работать.


Не смеши. Работать это дерьмо никогда не будет, точнее будет до ближайшей нестандартной ситуации в сети. И без разницы, какой протокол использовали.



N>Для SCTP, повторяю, тебе не нужны операции "убрать в начале" (а для обоих — "убрать с конца"). У тебя остаётся для приёмного буфера — очистить буфер, дописать в конец буфера, отдать буфер на рассмотрение. Для передающего — передать буфер целиком (добавить в конец списка), убрать переданный из начала списка. В случае действительно сложной политики стиля random early drop можно делать удаления из середины, в случае QoS — расставлять приоритеты, это будет общее с TCP, но это ты не описал.


Собственно, операция "убрать в начале" с количеством байт равным содержимому буфера и есть "очистить буфер". Так сказать, частный случай
Операция "убрать с конца" есть только потому, что я этот буфер использую и для подготовки пакетов к отправке. Заодно она оказалась удобной и для чтения. Резервируешь 10K, получаешь только 4K, остальные убираешь "с конца". Что касается "сложной политики", то в моих случаях она не используется, поэтому и операцию я не добавлял.

Собственно я не пытаюсь предложить универсальный API для буфера. Я всего лишь привёл пример буфера который может использоваться и для SCTP и для TCP. Безусловно, есть частные случаи, когда управление буфером будет требовать других операций, только обычно это определяется уже уровнем над транспортом, а не самим транспортом.

Резюме. Всё наше разногласие сводится к тезису о том, что тупой программер сможет делать более качественный код, если ему подсунуть SCTP вместо TCP. Если тебе хочет верить в эту глупость — то я ничего против не имею. Я же не настолько наивен. Для нормального программиста в базовом случае, разницы между SCTP и TCP нет, но документация для TCP проще и разобраться с ней получится быстрее. Собственно поэтому, большинство индусов знакомы (поверхностно) именно с TCP, а не с SCTP
Re[14]: epoll и reassembled TCP segments
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 24.04.15 09:37
Оценка:
Здравствуйте, v_andal, Вы писали:

_>Резюме. Всё наше разногласие сводится к тезису о том, что тупой программер сможет делать более качественный код, если ему подсунуть SCTP вместо TCP. Если тебе хочет верить в эту глупость — то я ничего против не имею. Я же не настолько наивен. Для нормального программиста в базовом случае, разницы между SCTP и TCP нет, но документация для TCP проще и разобраться с ней получится быстрее. Собственно поэтому, большинство индусов знакомы (поверхностно) именно с TCP, а не с SCTP


Они знакомы именно с TCP, потому что ему 40 лет и он успешно занял нишу, а SCTP активно всего 10 (а для Windows и вообще, считай, 0) и в эту нишу тяжело и нудно просачивается.

В остальном я согласен, я действительно предсказываю (не априорно, а на основании своего опыта), что тупой программер, поставленный на правильные рельсы, будет значительно меньше глупостей творить в случае SCTP, чем в случае TCP. У меня есть примеры успешного такого решения перед глазами. Один, самый эффективный, правда, не AF_INET+SCTP, а AF_UNIX+SOCK_SEQPACKET, но результат чрезвычайно вкусный. С SCTP похоже, но не настолько впечатляюще — может, потому, что у меня нет индусов.

N>>Вот именно поэтому я говорю, что из-за таких проблем надо в качестве подложки по умолчанию считать SCTP, а TCP применять только в трёх случаях — или неустранимое наследство, или требуется максимальная производительность на относительно мелких порциях, или поток вообще не ложится в концепцию сообщений крупнее октета (вряд ли это относится к чему-то более новому, чем telnet или ftp data).

_>Боже мой. Да тупой индус программер наворочает дерьма для SCTP столько же, сколько он его льёт для TCP. Он просто вообще не сможет разобраться, как с ним работать. Утонет на фазе создания ассоциации.

connect на конкретный хост и порт — что может быть проще? Сложности с построением ассоциации пропускаем.

N>>Фазы "смести начало буфера" в случае SCTP нет. "Удали обработанное" сводится к полной вычистке буфера. Так что тут реально проще. Но опять же дело не в этом. Я полностью согласен с тезисом, что при необходимости выжать максимум скорости получается множество слоёв сверху, по сравнению с которым работа с буфером — мелочь. Но см. выше про случаи из моего мира.

_>И эту разницу ты и считаешь "архисложной"? Только не надо меня опять отсылать к кодерам не знающим, что творят. Если для человека добавление одной-двух строчек кода — архисложно, то ему уже ничем не помочь. ИМХО

Ещё раз. Дело не в сложности как таковой. Дело в ловушке, которая позволяет пропустить этот шаг в лабораторных условиях TCP, показать, что и без него всё работает, и наплевать на проблемы тех, кто будет пользоваться результатом в реальных условиях. Идеальный программист в идеальных условиях, да, такого не допустит. Реальный чужой программист, заинтересованный не в результате, а в оплате времени и карьерных KPI — сделает, и пока ты пробьёшься через 5-10 административных слоёв для доказательства, что он был неправ, ты успеешь поседеть.

N>>Будут уметь, просто потому, что они натренированы, как собачки, написать заданное в инструкции имя сисколла и подставить ему заданные параметры, и это будет работать.

_>Не смеши. Работать это дерьмо никогда не будет, точнее будет до ближайшей нестандартной ситуации в сети. И без разницы, какой протокол использовали.

Пример такой нестандартной ситуации? (Файрволлы и NAT не предлагать)
The God is real, unless declared integer.
Отредактировано 01.05.2015 7:26 netch80 . Предыдущая версия .
Re[15]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 24.04.15 11:41
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, v_andal, Вы писали:


_>>Резюме. Всё наше разногласие сводится к тезису о том, что тупой программер сможет делать более качественный код, если ему подсунуть SCTP вместо TCP. Если тебе хочет верить в эту глупость — то я ничего против не имею. Я же не настолько наивен. Для нормального программиста в базовом случае, разницы между SCTP и TCP нет, но документация для TCP проще и разобраться с ней получится быстрее. Собственно поэтому, большинство индусов знакомы (поверхностно) именно с TCP, а не с SCTP


N>Они знакомы именно с TCP, потому что ему 40 лет и он успешно занял нишу, а SCTP активно всего 10 (а для Windows и вообще, считай, 0) и в эту нишу тяжело и нудно просачивается.


Да и сам протокол тяжеловат...

N>connect на конкретный хост и порт — что может быть проще? Сложности с построением ассоциации пропускаем.


Хе, чтобы пропустить то, что можно пропустить и выцепить то, что что нужно выцепить, талант надо иметь. А с талантом без разницы какой протокол штудировать

N>Ещё раз. Дело не в сложности как таковой. Дело в ловушке, которая позволяет пропустить этот шаг в лабораторных условиях TCP, показать, что и без него всё работает, и наплевать на проблемы тех, кто будет пользоваться результатом в реальных условиях.


Так блин, такой программист и partial read в SCTP проигнорирует, на тех же условиях.

N>Пример такой нестандартной ситуации? (Файрволлы и NAT не предлагать)


А если подсунуть удалённому хосту заведомо большой пакет (выходящий за пределы системных буферов), вынуждающий его скармливать этот пакет в несколько приёмов?
Или мы говорим исключительно о протоколах внутреннего использования? Или начнёшь заверять, что индус отказывающийся верить, что в TCP пакет может прийти разбитым, вдруг чудесным образом поверит, что в SCTP это возможно? И это после того, как его заверят, что SCTP в отличие от TCP сохраняет границы пакета? Увольте, в такие чудеса я не верю.
Re: epoll и reassembled TCP segments
От: Cruser Украина  
Дата: 24.04.15 14:14
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...


L>Пишу простенький веб-сервер сугубо для своих нужно, нужно отправлять и получать JSON.


Нужен буффер для чтения, который умещает максимальный json запрос. Читать в буффер данные, пока не придёт последняя } скобка — это и будет
json запрос. А то, что осталось в буфере сдвигать в начало и по новой.
Re[14]: epoll и reassembled TCP segments
От: Слава  
Дата: 25.04.15 22:09
Оценка:
Здравствуйте, v_andal, Вы писали:

_>Боже мой. Да тупой индус программер наворочает дерьма для SCTP столько же, сколько он его льёт для TCP. Он просто вообще не сможет разобраться, как с ним работать. Утонет на фазе создания ассоциации. От глупости и незнания нельзя защититься более продвинутым протоколом. Поэтому, подобные аргументы в топку. Качественная программа не будет иметь значительных отличий.


Вот несколько умных мыслей из другого источника:

> >Также как гонять unbounded потоки байт по TCP малой полезности идея (в 100% случаев нужны сообщения, а не поток)

>
> Абсолютно голословное утверждение. Сообщения с проверкой доставки совершенно бесполезны при вещании потокового видео, в интерактивных играх, при передаче низкоприоритетной телеметрии и т.п. До тех пор, пока каналы передачи данных не будут гарантировать доставку данных за определенный промежуток времени, будут востребованы потоковые протоколы, позволяющие терять определенный процент данных в обмен на плавное ухудшение качества сервиса. Например, показывать вместо 48 кадров в секунду 24 лучше чем вообще прерывать трансляцию видео.

Комментатор сознательно решает не замечать логику аргумента.

Вещание потокового видео — серия относительно коротких файлов (в районе мегабайта на файл). Интерактивная игра — серия сообщений, либо HTTP (где один фетч — это по сути один мессадж), либо тот же WebSocket — где обмен сообщениями идёт через message-oriented транспорт, или тупо наверчивают фрейминг а-ля "тут пишем 4 байта длины, потом JSON". Это всё каждый факин раз изобретается заново.

Передача низкоприоритетной телеметрии, это, в лучшем случае, UDP, в среднем — line separated TCP (тот же фрейминг, но не length-prefixed, а \n-separated), а в худшем — SNMP, который суть что? Правильно, TLV.

SMTP — это message oriented транспорт. Один заголовок SMTP-exchange (типа EHLO) или боди целиком — это отдельные сообщения. Сейчас парсинг их осуществляется иногда поиском завершителя строки \n, иногда — поиском пустой строки (\n\n), иногда — поиском точки на пустой строке. В одном и том же факин протоколе! Нет уж, дайте нам нативный message oriented transport, дальше уж мы сами накрутим поверх этого логику, надоело парсить в телах \n-ы.
Re[15]: epoll и reassembled TCP segments
От: v_andal Германия  
Дата: 29.04.15 10:19
Оценка:
Здравствуйте, Слава, Вы писали:

С>SMTP — это message oriented транспорт. Один заголовок SMTP-exchange (типа EHLO) или боди целиком — это отдельные сообщения. Сейчас парсинг их осуществляется иногда поиском завершителя строки \n, иногда — поиском пустой строки (\n\n), иногда — поиском точки на пустой строке. В одном и том же факин протоколе! Нет уж, дайте нам нативный message oriented transport, дальше уж мы сами накрутим поверх этого логику, надоело парсить в телах \n-ы.


SMTP протокол это динозавр. Он возник во времена когда к 8-битным данным плохо относились, да и пропускная способность ценилась. Поэтому он чисто текстовый, со всеми вытекающими заморочками. Сейчас систему email можно вообще всю иначе сделать, только кто же будет работающую систему ломать? Вон даже IPv6 никак не оживёт, хоть вроде бы и нужен, что уж про email говорить, когда здесь и так всё работает. Так что можно ныть на тему заморочности SMTP или HTTP, только парсить их всё равно придётся.

Ну а по-поводу "нативный message oriented transport" я уже раньше сказал, если кому-то нужен этот костыль — пользуйтесь на здоровье. Я не вижу никакой сложности в разборе потока. Основная сложность всегда в логике накрученной поверх полученных данных. Безусловно, схема "длина пакета + пакет" удобнее, чем "найди конец пакета", но и это не катастрофа. С другой стороны, протоколы на основе ASN со всеми их бессчётными TLV тоже доводят до белого каления.

На мой взгляд, сетевой транспорт не должен заботится о границах данных, это не диван, цифровые данные можно дробить и склеивать без особых последствий. Собственно разбивка нужна, так как сетевое железо не блещет однообразием возможностей. Склеивание же на системном уровне осложняется размерами буфера, так что гораздо разумнее оставить склеивание конечному потребителю, по крайней мере это последовательнее, чем часть пакетов склеивать, а часть отдавать кусками. ИМХО.

Если уж мечтать об усовершенствованиях, то лучше мечтать о более совершенном routing. В общем-то мультихом мог бы быть реализован на этом уровне, без того, чтобы захламлять софт
Re: epoll и reassembled TCP segments
От: Lepsik Гондурас https://www.kirdyk.club/
Дата: 30.04.15 18:04
Оценка:
L>Пишу простенький веб-сервер сугубо для своих нужно, нужно отправлять и получать JSON.

node.js
Re[13]: epoll и reassembled TCP segments
От: Sinclair Россия https://github.com/evilguest/
Дата: 28.05.15 09:28
Оценка:
Здравствуйте, netch80, Вы писали:

N>Я несколько раз (два — сам, ещё пару — через ближайших коллег, и слышал ещё) сталкивался со следующей ситуацией. Есть какая-то самопальная железка или прошивка к чему-то IPMI-BMC-подобному, в которую года 3 назад из-за улучшения аппаратных возможностей впихнули Linux, обрадовались облегчению, уволили всех толковых и посадили толпу выпускников заборостроительного ПТУ. Железка регулярно посылает данные мониторинга (телеметрию, whatever). Её можно отправлять по UDP, тогда проблем с границами нет, но есть шанс потерь. Кто-то из среднего начальства взвивается и говорит "потерь быть не должно", люди переключаются на TCP, и тут оказывается, что автор отправляющего агента Кришназевул Абдулкумар (иногда его зовут Ху Ли) искренне считает, что что одним send() отправлено, то одним recv() и получится, и никакой маркировки длины или эскейпинга не придумывает (каждый байт у него на строжайшем учёте, за лишний байт бьют по рукам и изгоняют в дерёвню, формат запутан и недиагностируем). Всё работает в его лаборатории на коленке, а когда начинаются проблемы с реальной загрузкой приложения и сети, он и его начальство (у которого мозгов ещё меньше, но больше наглости и изворотливости) посылают ко всем индийским лешим, утверждая, что проблемы не его стороне. Прочитать, что TCP отдаст за один recv() два пакета, и понять границы после этого невозможно, уже не укладывается в его квадратно-гнездовую башку. Вопрос не в максимальной производительности или количестве данных за один вызов, это не стоит проблемой — внутренняя обработка значительно сложнее сисколла. Вопрос в корректности передачи и разбора.

N>Вот именно поэтому я говорю, что из-за таких проблем надо в качестве подложки по умолчанию считать SCTP, а TCP применять только в трёх случаях — или неустранимое наследство, или требуется максимальная производительность на относительно мелких порциях, или поток вообще не ложится в концепцию сообщений крупнее октета (вряд ли это относится к чему-то более новому, чем telnet или ftp data).
Это очень интересный изолированный сценарий: переход от датаграммного протокола к потоковому. Вот для него, конечно же, tcp — плохой выбор, надо переходить от датаграммного протокола без гарантий к датаграммному с гарантиями — например к sctp.
Хотя в целом это всё — попытка решить административную проблему техническими средствами, что заведомо невозможно.
Мы говорим о весьма сложной задаче — проектирование прикладного протокола поверх чего-то более-менее стандартного.
Это задача явно за пределами компетентности ПТУшника, потому что network is hard. Если разработчик не в состоянии понять, почему udp не подходит для потока или tcp для датаграмм, то он и всё остальное тоже гарантированно протупит. У него шансы получить работающую реализацию примерно такие же, как и выиграть в Вегасе.

А если мы говорим о реализации готового протокола, то всё гораздо лучше — потому что проектирование обычно выполнено вменяемыми людьми.
В частности, в HTTP вопрос детектирования границ решается однозначно и независимо от границ каких-либо пакетов.
И все остальные протоколы, построенные поверх потокового соединения, имеют встроенные возможности детектирования границ.
HTTP в этом смысле чрезмерно сложен — поскольку у него в одних случах границы определяются ескейпингом (плюс специальные меры для изъятия искусственных границ), а в других — префиксом длины. К счастью, код разбора протокола можно либо взять готовый, либо построить из простых кирпичиков, которые убирают всю эту адову мешанину с глаз долой.

Рукопашно-реализованный протокол обычно строится каким-то одним способом, и его навелосипедить проще, чем построить HTTP сервер или HTTP клиент с нуля.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: epoll и reassembled TCP segments
От: dad  
Дата: 30.06.15 14:39
Оценка:
используй библиотеку http, например, libevhtp
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.