The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"send и select"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Изначальное сообщение [ Отслеживать ]

"send и select"  +/
Сообщение от drone (ok) on 03-Апр-11, 02:24 
Не могу никак разобраться.
Использую неблокирующие сокеты и select.
Программа принимает соединения, читает и пишет в клиентские сокеты, все работает.
Но всплыла проблема:
если попробовать отослать относительно большой объем данных (150 кб),
то отсылается примерно 33864 байт, а далее шлется маленькими кусочками
байт по 100 с интервалом по несколько секунд.
С чем может быть связано такое поведение?

На всякий случай:
вот синтаксис select:

select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
         struct timeval *timeout);

по событию на readfds для клиентского сокета я читаю данные, все нормально.
по событию на writefds для клиентского сокета я ничего не делаю.
Просто в произвольном месте программы вызываю send(sclient, buffer, 150*1024, 0).
Это правильно?

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "send и select"  +/
Сообщение от C on 03-Апр-11, 02:44 
TCP ?
читать про алгоритм нагла?
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

2. "send и select"  +/
Сообщение от drone (ok) on 03-Апр-11, 02:45 
TCP
Программа уже работает несколько лет. Но видимо просто больших данных не ходило.
Ответить | Правка | ^ к родителю #1 | Наверх | Cообщить модератору

3. "send и select"  +/
Сообщение от drone (ok) on 03-Апр-11, 04:11 
Не знаю, на сколько правильно решение, сделал так:

когда нужно заслать большой объем, пишу

fcntl(sock, F_SETFL, O_DIRECT);
int bytes_sent = send(sock, buffer_send, sz_buf_send, 0);
fcntl(sock, F_SETFL, O_NONBLOCK);

Вроде работает, по несколько мегабайт пуляет нараз.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

4. "send и select"  +/
Сообщение от C on 03-Апр-11, 18:00 
еще раз говорю
man алогоритм нагла

и отключается он через ioctl
но прежде чем это делать
изучите внимательно все статьи в интернете на эту тему

Ответить | Правка | ^ к родителю #3 | Наверх | Cообщить модератору

5. "send и select"  +/
Сообщение от drone (ok) on 06-Апр-11, 20:13 
При чем здесь алгоритм нагла?
Он как я понял склеивает мелкие сообщения.
А тут большой объем сразу нормально не шлется.

Прочитал, отключается он так:

const int on = 1 ;
setsockopt(sclient, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));


Сделал так, ничего не изменилось.
При выставлении флага:

fcntl(sock, F_SETFL, O_DIRECT);

Все отправляется быстро в локалке.
Однако так я перевожу сокет в блокирующмй режим, основной цикл сервера приостанавливается.
Есть какие0нибудь идеи еще?

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

6. "send и select"  +/
Сообщение от guest email(??) on 06-Апр-11, 22:39 
> Есть какие0нибудь идеи еще?

Вы для начала определитесь блокирующие у вас сокеты или нет.

> fcntl(sock, F_SETFL, O_DIRECT);

Первый раз такое вижу, в чем смысл O_DIRECT для сокета? где почитать?

Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

7. "send и select"  +/
Сообщение от drone (ok) on 07-Апр-11, 11:45 
FreeBSD:

man fcntl
....................
     O_NONBLOCK   Non-blocking I/O; if no data is available to a read(2) sys-
                  tem call, or if a write(2) operation would block, the read
                  or write call returns -1 with the error EAGAIN.

     O_APPEND     Force each write to append at the end of file; corresponds
                  to the O_APPEND flag of open(2).

     O_DIRECT     Minimize or eliminate the cache effects of reading and writ-
                  ing.  The system will attempt to avoid caching the data you
                  read or write.  If it cannot avoid caching the data, it will
                  minimize the impact the data has on the cache.  Use of this
                  flag can drastically reduce performance if not used with
                  care.

     O_ASYNC      Enable the SIGIO signal to be sent to the process group when
                  I/O is possible, e.g., upon availability of data to be read.
....................


У меня неблокирующие, один цикл, опрос сокетов по select. Стандартная схема.
Но чтобы большой файл передался быстро (см первое сообщение), временно приходится переводить в блокирующий режим.

O_NONBLOCK | O_DIRECT
Не дает эффекта. Работает как неблокирующий по старому, и проблема остается.

Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

8. "send и select"  +/
Сообщение от guest email(??) on 07-Апр-11, 12:19 
> FreeBSD:

Дык маны, я и сам читать умею... и в курсе как он работает для дискового I/O, но причем тут сокеты?

> У меня неблокирующие, один цикл, опрос сокетов по select. Стандартная схема.

Вы там пишите:
>по событию на writefds для клиентского сокета я ничего не делаю.

А зачем тогда селект насилуете?
>Просто в произвольном месте программы вызываю send(sclient, buffer, 150*1024, 0).

Кода то вы не показываете. Да и спрашиваете как-то мутно, можно только гадать.
Видимо вас удивляет почему при O_NONBLOCK этот send() не отсылает все сразу?

> Но чтобы большой файл передался быстро (см первое сообщение), временно приходится переводить
> в блокирующий режим.

O_NONBLOCK на скорость передачи сам по себе никак не влияет.

Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

9. "send и select"  +/
Сообщение от drone (ok) on 07-Апр-11, 13:24 
>> Видимо вас удивляет почему при O_NONBLOCK этот send() не отсылает все сразу?

Не держите меня за дурака =)
Я прекрасно понимаю, что оно не должно сразу.
Повторю, схема стандартная, прога рабоает уже несколько лет.
Просто больших данных за раз не передавали.
При попытке отослать большие данные шлется не просто медленно, а присходит
какая-то аномалия. После пересылки n-го количества килобайт начинает слать
байт по 100 с интервалами по несколько секунд. И это в локалке.
То есть точно не в скорости передачи дело.

>>  O_NONBLOCK на скорость передачи сам по себе никак не влияет.

Это понятно. Но оно устраняет вышеописанныу аномалию.

>>>>по событию на writefds для клиентского сокета я ничего не делаю.
>>А зачем тогда селект насилуете?

Селект насилую для определения, пришли ли данные извне.
Как только пришли, селект радостно об этом сообщает (после его вызова разумеется) и я начинаю читать.

Потом просто пишу с помощью send.

Код не привожу, потому что большой. Резать кучу надо.
Могу привести крд начала цикла:


    while(true)
    {
        //////// POLLING SOCKETS ////////

        FD_ZERO(&fdset_r);
        FD_ZERO(&fdset_w);
        FD_SET(sock, &fdset_r);
        FD_SET(sock, &fdset_w);

        int max_fd = sock;

        for(map<int, client_info> ::iterator Iter = map_clients.begin(), End = map_clients.end(); Iter != End; ++Iter)
        {
            int sclient = Iter->first;
            FD_SET(sclient, &fdset_r);
            if(sclient > max_fd) max_fd = sclient;
        }

        timeval poll_timeout;
        bzero(&poll_timeout, sizeof(timeval));
        poll_timeout.tv_sec = poll_timeout_param;
        int ret = select(max_fd + 1, &fdset_r, &fdset_w, NULL, &poll_timeout);

        if(ret > 0)
        {
            if(FD_ISSET(sock, &fdset_r) || FD_ISSET(sock, &fdset_w))
            {
                int sclient = accept(sock, NULL, NULL);
                if(sclient > 0)
                {
// собственно появилось новое соединение
........... куча кода .........
// далее проверяем, есть ли байты на клиентских сокетах и читаем:

            for(map<int, client_info> ::iterator Iter = map_clients.begin(), End = map_clients.end(); Iter != End; ++Iter)
            {
                int sclient = Iter->first;

                if(FD_ISSET(sclient, &fdset_r))
                {
                    FD_CLR(sclient, &fdset_r);
// данные есть, можно читать



Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

10. "send и select"  +/
Сообщение от guest email(??) on 07-Апр-11, 14:42 
> Код не привожу, потому что большой. Резать кучу надо.

У вас проблемы с отправкой, но показываете вы accept и проверку к готовности recv()
с таким же успехом парсинг командной строки могли бы выложить...

> Могу привести крд начала цикла:

Это ни о чем (ну кроме того, что пихать listen() сокет в fdset_w бессмысленно)

Ответить | Правка | ^ к родителю #9 | Наверх | Cообщить модератору

11. "send и select"  +/
Сообщение от drone (ok) on 07-Апр-11, 15:38 
>> Код не привожу, потому что большой. Резать кучу надо.
> У вас проблемы с отправкой, но показываете вы accept и проверку к
> готовности recv()
> с таким же успехом парсинг командной строки могли бы выложить...
>> Могу привести крд начала цикла:
> Это ни о чем (ну кроме того, что пихать listen() сокет в
> fdset_w бессмысленно)

Повторяю, я просто в коде делаю send(sclient, ...)
И все.
Вот и не выкладывал код, потому что не надо.
fdset_w добавил на всякий случай, ничего не делаю по нему.

Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

12. "send и select"  +/
Сообщение от guest email(??) on 07-Апр-11, 15:58 
При дефолтном SO_SNDBUF и O_NONBLOCK ваш send() за раз отправить 150кб не в состоянии, соответственно передача рвется на куски, показать нужную часть кода вы категорически отказываетесь и предлагаете угадать, а как же оно у вас там устроено... Давайте гадать:
Когда send() позовут следующий раз?
Варианта два (код то вы не показываете)
1 хз знает когда, т.е. в момент когда select() сработает на чтение либо вывалиться по таймауту.
2 у вас там жрущий проц цикл вокруг send() с проверкой на EAGAIN
Ответить | Правка | ^ к родителю #11 | Наверх | Cообщить модератору

14. "send и select"  +/
Сообщение от drone (ok) on 07-Апр-11, 23:24 
> При дефолтном SO_SNDBUF и O_NONBLOCK ваш send() за раз отправить 150кб не
> в состоянии, соответственно передача рвется на куски, показать нужную часть кода
> вы категорически отказываетесь и предлагаете угадать, а как же оно у
> вас там устроено... Давайте гадать:
> Когда send() позовут следующий раз?
> Варианта два (код то вы не показываете)
> 1 хз знает когда, т.е. в момент когда select() сработает на чтение
> либо вывалиться по таймауту.
> 2 у вас там жрущий проц цикл вокруг send() с проверкой на
> EAGAIN

Да господи! Читайте первый пост. Процитирую:
>> Просто в произвольном месте программы вызываю send(sclient, buffer, 150*1024, 0).

Обычно это после того, как пришли данные на сокет и обработались. Шлется ответ.
Ничего там не жрется.
То что оно не может отослать 150 кб за раз это я тоже понимаю, админю и прогаю почти 10 лет. Вопрос не в том, почему частями, а в том, откуда взялись эти дикие задержки.

Ответить | Правка | ^ к родителю #12 | Наверх | Cообщить модератору

15. "send и select"  +/
Сообщение от C on 07-Апр-11, 23:46 
> тоже понимаю, админю и прогаю почти 10 лет. Вопрос не в

тоесть если у вас такой большой опыт
вы сможете набросать код на несколько строк
клиент-сервера
который демонстрируют такую особенность?

скомпилять и запустить каждый у себя локально сможет! )


Ответить | Правка | ^ к родителю #14 | Наверх | Cообщить модератору

16. "send и select"  +/
Сообщение от drone (ok) on 08-Апр-11, 00:05 
>> тоже понимаю, админю и прогаю почти 10 лет. Вопрос не в
> тоесть если у вас такой большой опыт
> вы сможете набросать код на несколько строк
> клиент-сервера
> который демонстрируют такую особенность?
> скомпилять и запустить каждый у себя локально сможет! )

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

Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

17. "send и select"  +/
Сообщение от guest email(??) on 08-Апр-11, 10:00 
> вы сможете набросать код на несколько строк
> клиент-сервера
> который демонстрируют такую особенность?

человек напрочь не понимает, что на не блокируемом сокете с дефолтными буферами его
send(,,150*1024,) никогда не вернет 150*1024 т.к. за 10лет не дочитал man send

Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

19. "send и select"  +/
Сообщение от drone (ok) on 09-Апр-11, 04:14 
-------------
Ответить | Правка | ^ к родителю #17 | Наверх | Cообщить модератору

18. "send и select"  +/
Сообщение от guest email(??) on 08-Апр-11, 10:23 
> Да господи! Читайте первый пост. Процитирую:
>>> Просто в произвольном месте программы вызываю send(sclient, buffer, 150*1024, 0).

Да не нервничайте вы так.


> Обычно это после того, как пришли данные на сокет и обработались. Шлется
> ответ.
> Ничего там не жрется.
> То что оно не может отослать 150 кб за раз это я
> тоже понимаю, админю и прогаю почти 10 лет. Вопрос не в
> том, почему частями, а в том, откуда взялись эти дикие задержки.

Ответ был, повторю: следующий вызов send() происходит через случайное время, а именно либо по готовности одного из дескрипторов к чтению либо по истечению таймаута select()
Или вы все-таки не понимаете, что ваш send(sclient, buffer, 150*1024, 0) всегда возвращает <= размера SO_SNDBUF?

Ответить | Правка | ^ к родителю #14 | Наверх | Cообщить модератору

20. "send и select"  +/
Сообщение от drone (ok) on 09-Апр-11, 04:20 
>[оверквотинг удален]
>> ответ.
>> Ничего там не жрется.
>> То что оно не может отослать 150 кб за раз это я
>> тоже понимаю, админю и прогаю почти 10 лет. Вопрос не в
>> том, почему частями, а в том, откуда взялись эти дикие задержки.
> Ответ был, повторю: следующий вызов send() происходит через случайное время, а именно
> либо по готовности одного из дескрипторов к чтению либо по истечению
> таймаута select()
> Или вы все-таки не понимаете, что ваш send(sclient, buffer, 150*1024, 0) всегда
> возвращает <= размера SO_SNDBUF?

---------------------

Ответить | Правка | ^ к родителю #18 | Наверх | Cообщить модератору

13. "send и select"  +/
Сообщение от C on 07-Апр-11, 21:47 
> fcntl(sock, F_SETFL, O_DIRECT);

нет такой стратегии O_DIRECT для сокета
она только для fs работает

может по O_DIRECT срабатывает какая то дефолтовая стратегия
которая сбрасывает принудительно буфферы
но желания колупать код бсд что бы проверить, у меня нет


Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

21. "send и select"  +/
Сообщение от drone (ok) on 09-Апр-11, 05:11 
Всем спасибо за ответы, я разобрался.
Проблема была в не правильном понимании работы неблокирующих сокетов.
Я думал, что вызвав send, _все_ данные положатся во внутренний буфер и сами зашлются, а занчение, которое возвращает send - это количество данных, отправленное на данный момент.
Для меня было новостью, что после этого оно ничего слать никуда не будет. А хвост моего буфера останется не отосланным.
Я подохревал подвох, поэтому написал в своем первом сообщении:
>> по событию на writefds для клиентского сокета я ничего не делаю.

Теперь я понимаю, что в этом месте нужно досылать не отосланные данные.
Видимо криво излагаю свои мысли, раз такая дискуссия разрослась.
Посыпаю свою голову пеплом и еще раз всем спасибо =)

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

22. "send и select"  +/
Сообщение от guest email(??) on 09-Апр-11, 08:38 
> Я подохревал подвох, поэтому написал в своем первом сообщении:
>>> по событию на writefds для клиентского сокета я ничего не делаю.

В вашем исходном посте смутило, да и сейчас смущает это:
>то отсылается примерно 33864 байт, а далее шлется маленькими кусочками
>байт по 100 с интервалом по несколько секунд.

Совершенно не понятно откуда берутся кусочки по 100 байт если send() на клиента все-таки один. Если вы с этим разобрались может расскажите?

Ответить | Правка | ^ к родителю #21 | Наверх | Cообщить модератору

23. "send и select"  +/
Сообщение от drone (ok) on 09-Апр-11, 13:04 
>> Я подохревал подвох, поэтому написал в своем первом сообщении:
>>>> по событию на writefds для клиентского сокета я ничего не делаю.
> В вашем исходном посте смутило, да и сейчас смущает это:
>>то отсылается примерно 33864 байт, а далее шлется маленькими кусочками
>>байт по 100 с интервалом по несколько секунд.
> Совершенно не понятно откуда берутся кусочки по 100 байт если send() на
> клиента все-таки один. Если вы с этим разобрались может расскажите?

Там от клиента приходили сообщения с таким интервалом видимо.
Тоже асинхронно, и сервер на них лтвечал, поэтому я предположил, что это те данные досылаются.
Факт прихода этих данных я наблюдал на клиентской машине.
Так как данных много, я о конца передачи не дожидался.
Весь прием замораживался на клиенте, потому что передача осуществляется
посредством некого протокола. Когда большие данные начали передаваться, первым пошел заголовок с CRC и общим размером пакета.
В итоге часть паета пришла, далее стало дополняться данными от маленьких запорстов байт по 100. Как-то так.

Ответить | Правка | ^ к родителю #22 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру