The OpenNET Project / Index page

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




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
TCP/IP в режиме реального времени, !*! Gor, 21-Июл-07, 14:11  [смотреть все]
Я некоторое время назад задавал здесь вопросы по Сервер-Клиент -программам дла TCP/IP для режима реального времени,-часть кода можно увидеть в темах, которые я открывал раньше(хотя там и изменилось многое).

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

Я проследил за пересылаемыми пакетами в Wireshark. Там видно, что клиент посылает постоянно 23 байт строки, но потом, после определенного времени он посылает за раз 5 пакетов,- то биш 115 байт. Я посмотрел, сколько времени проходит между пакетами,- 1,3 мс при пересылке данных и 0,2 мс при пересылке подтверждения. Затем по непонятной мне причине подтверждение приходит через 6,9 мс, за это время на сервере собирается 5 пакетов, и они все отсылаются. Затем ещё некоторое время продолжается утихомиривание этого процесса и через некоторое время всё возвращается к обычной работе.

Может ли кто мне подсказать почему так циклично время от времени увеличивается время пересылки подтверждения и как этого можно избежать?

Пытался отключать нагл-алгоритм(TCP_NODELAY), но это ещё более ухидшило картину.
Единственное решение, которое я пока нашёл,- я вставил паузу между отсылками сообщений 5 мс и избавился таким образом от нежелательных одновременных пересылок множества пакетов за раз. Но таким образом я могу пересылать гораздо меньше сообщений в единицу времени, а это нежелательно.

  • TCP/IP в режиме реального времени, !*! vic, 18:09 , 22-Июл-07 (1)
  • TCP/IP в режиме реального времени, !*! int _0dh, 12:31 , 23-Июл-07 (2)
  • TCP/IP в режиме реального времени, !*! perece, 18:31 , 23-Июл-07 (3)
    • TCP/IP в режиме реального времени, !*! Gor, 19:27 , 25-Июл-07 (4)
      >> часть кода можно увидеть в темах, которые я открывал раньше(хотя там и изменилось многое).
      >
      >ссылочку давай. поиск че-то ниф не рулит..
      >
      >там в сокет не через fdopen/sprintf пишется случайно???
      >
      >\^P^/

      Клиент:

      for(i=10000;i<=20000;i++)
              {
                     gettimeofday((struct timeval *) &tv, 0 );
                actual_time = localtime( &(tv.tv_sec ) );
                strftime(vorbuffer,9, "%H:%M:%S", localtime( &(tv.tv_sec ) ) );

                length=sprintf(buffer,"%ld\t%s.%06ld\n\r",i,vorbuffer, tv.tv_usec);
          
                send(sock_fd, buffer, length, 0);        
              }

      Сервер:
      char puffer_our_time[9];
                length = recv(client_fd, puffer_find_number_time,23, 0);
              puffer_find_number_time[length]='\0';
                      
              gettimeofday( &tv, 0 );
              actual_time = localtime( &(tv.tv_sec ) );
              strftime( puffer_our_time, 9, "%H:%M:%S", localtime( &(tv.tv_sec ) ) );
              if (length != 0)
                    {
                  printf("%s.%ld\t\t%s",puffer_our_time,tv.tv_usec,puffer_find_number_time);
                }
              else
                {      printf("Connection closed by remote host.\n");
                           break;
                }

    • TCP/IP в режиме реального времени, !*! Gor, 19:32 , 25-Июл-07 (5)
      Насчёт ошибки в коде, - вполне возможно, опыта у меня толком в программировании практически нету.

      Что касается UDP,- попробовал сегодня, однако теряются некоторые сообщения, как и положено, насколько я понимаю в udp. Но зато скорость на много порядков выше и никаких проблем с пересылкой нескольких пакетов за один раз...

      Что меня удивляет с udp,- когда контролирую пересылку с помощью Wireshark, вижу, что все пакеты были отосланы и находились в проводе. Но в сохранённом файле некоторых сообщений не хватает. В конце персылки совсем выпадают последние 20-30 сообщений. Если я правильно понимаю,- это означает, что проблемы возникают н апринимаюъей стороне. Маленкий буфер? Или что могло бы это быть ещё.

      Для информации,- связь происходит в маленькой сетке с одним хабом, двумя машинами(с embedded Linux,PowerPC) и контролирующим работу Ноутбуком, где и работатет Wireshark.  

      • TCP/IP в режиме реального времени, !*! tester, 01:49 , 27-Июл-07 (6)
        • TCP/IP в режиме реального времени, !*! Gor, 09:53 , 27-Июл-07 (7)
          >В юдипи нет такого понятия как размер окна. Поэтому там все пакеты
          >пуляються в сеть сразу. Соответственно: буфера не хватило - пакеты потерялись...

          Я тоже уже об этом подумал,- сегодня хотел как раз посмотреть, как буффер в УДП увеличить можно.

          >Может кстати в TCP проблемы из-за размера окна. Мож подтверждения задерживаются...

          Окно достаточно большое на обоих машинах декларируется,-посмотрю повнимательнее, что с ним может быть, спасибо. Подтверждения задерживаются,- это как раз то, что и происходит. Через практически одинаковое время каждый раз.

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

          >Может в каждом пакете устанавливать флаг PUSH?

          Он устанавливается автоматически у меня, практически всегда,- почему иногда нет,- не знаю...

      • TCP/IP в режиме реального времени, !*! vic, 17:45 , 27-Июл-07 (8)
        • TCP/IP в режиме реального времени, !*! Gor, 23:35 , 27-Июл-07 (9)
          >Все верно, пакеты могут теряться, скорость выше (отсутствие ожидания подтверждения).
          >Обработка потери пакетов в этом случае на стороне приложения.
          >
          >Как я понял передача идет на максимуме возможностей?

          Да, я пробовал на максимуме,- в этом случае в TCP/IP пересылаются практически всегда множество пакетов за один раз.Возможное решение,- встроенная пауза в 5мс, тогда всё работает чётко, но не так быстро.
          В UDP/IP теряются до 25% сообщений на максимуме. При паузе в 0,5мс,- все пакеты доходят без потерь.
          При этом я также попробовал CAN-бус,- он при задержке в 0,5 мс оказывается быстрее тисипи и удп с такими же задержками, при том что работает на 250Кбит/с!!!

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

          Это идея!!! Спасибо большое,- обязательно проверю работу программы без "Ваершарка". При УДП вижу в нём при этом исключительно удп сообщения от одного к другому, то биш параллельно ничего не происходит. В ТСП конечно тратиться время на подтверждение, но так как отсылающая сторона ничего не посылает, пока не получит ответа,- коллизий должно бы не происходить. Единственное слабое место,- "Ваершарк". Интересно, как он работает? Принимает поток и направлаяет его дальше?  

          >Дальше, сетевая карта
          >может работать на приемной стороне чуть медленнее чем положено, например что-то
          >фигово с сопряжением с системной платой (наука о контактах) как результат
          >потери на приемной стороне.

          Сетевой карты как таковой нет,- всё происходит в процессоре(MPC 5200B). Проверить скорость,- хм, даже не знаю как,- приходиться полагаться на документацию, а в реализации конечно могут быть глюки...

          >[оверквотинг удален]
          >
          >выш вы приводили кусок кода сервера где:
          >      if (length != 0)
          >            
          >  {
          >            
          >printf("%s.%ld\t\t%s",puffer_our_time,tv.tv_usec,puffer_find_number_time);
          >          }
          >Это в файл перенаправлено или на консоль? (консоль имеет свои задержки).
          >stdout - строчная буфферизация. может быть причиной.

          Я перенаправляю с консоли в файл( ./server > abc.txt), - чтобы не тратилось время на вывод сообщений и отправку их на консоль, которая находится на ноуте(у машин нет ни экранов, ни клавиатуры)-дополнительное время и коллизионы. Кроме того могу затем внимательно весь файл изучить. Пробовал раньше и с (fprintf),- там примерно те же проблемы.

          >Как выше писал может причина с fsync. Можно попробовать проверить так -
          >создать мега-буфер (так чтобы туда минут 5 лога поместилось) в памяти
          >и писать не в файл (fprintf), а в этот буфер (sprintf),
          >когда буфер забьется сбросить его в файл и потом проанализировать, а
          >были ли задержки в таком случае.

          Посмотрел сейчас ман к fsync,- получается с его помощью я могу писать пакеты без буфферизации в printf i fprintf(хотя есть ли она в fprintf не знаю точно) сразу в память, так? Я пока не понял, как мне это сделать, надо будет в понедельник посмотреть на работе повнимательнее. Также попробую с мега-буфером,- спасибо большое за идею!

          >По поводу PUSH - есть опция включающая этот режим (setsockopt(TCP_NODELAY) - отключить
          >алгоритм Нэгла), без нее флаг не ставиться если не системная настройка
          >(может быть какой-то тюнинг сделан в той же embedded linux?).

          PUSH в тсп у меня обычно включён по умолчанию. Видимо тюнинг. Хотя я пробовал "выключать" режим Нэгла, - тогда пакеты отсылались сразу по мере поступления, но после десятого(в среднем) отсылка приостанавливалась и шло ожидание ответа или возможно просто ответ поспевал к этому времени. В момент приёма и обработки подтверждения скапливалась очередная порция пакетов,- которые и отсылались "кучкой" в следующем сообщении(обозначил так евернет-пакет, так как пакет под свой стринг определил ранее).

          >пользователь обычный или рут? это к вопросу приоритета, а мало ли... :)
          >это я уже фантазирую.

          на машинах рут, других работающих приложений нет.

          • TCP/IP в режиме реального времени, !*! anonymous, 03:36 , 28-Июл-07 (10)
            • TCP/IP в режиме реального времени, !*! Gor, 23:26 , 29-Авг-07 (11)
              >Нет, не то.  Может быть проблема в том, что fsync запускается
              >для сброса буферов на диск раз в сколько-то-там миллисекунд, и это
              >тормозит отпрвку пакетов вашей программой.  Предложение было создать мега-буфер, для
              >того, чтобы не дёргать диск, и соответственно, fsync.

              Здравствуйте, загрузили на работе другими делами и не было времени на это. А теперь надо в спешке опять этим заниматься,- как всегда:-)

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

              До тех пор, пока речь шла о маленьких обьёмах в размере нескольких килобайт, всё было ок. Когда увеличивается количество пересылаемых сообщений(а оно должно быть порядко миллиона в итоге, - размер до десятков мегабайт  (размер оперативки позволяет,- постоянно около 100 МБ свободны)),- получатель недополучает сообщения и так как я ещё не встроил никакой системы выхода из цикла for(), программа просто ждёт поступления новых сообщений.
              Как встроить этот выход пока не решил, - может быть что-то подскажете?
              В книге Стивенса нашёл способ с включением таймаута(SIGALARM) (если некоторое время не приходят сообщения по удп, то программа прерывается). Но что за библиотеки необходимо там использовать, я ещё не нашёл.

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

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

              • TCP/IP в режиме реального времени, !*! anonymous, 03:26 , 30-Авг-07 (12)
                • TCP/IP в режиме реального времени, !*! Gor, 09:18 , 30-Авг-07 (13)
                  >Память лучше выделить сразу большой кусок, так как при realloc() данные могут
                  >быть перемещены в памяти, а знаит, процессор будет занят тупым копированием
                  >данных.  fprintf() лучше заменить на системные вызовы open(), read(), close(),
                  >потому что мало ли какие буферы он сам выделяет и сколько
                  >на это времени тратит.

                  Спасибо болшое за советы,- сейчас попробую.

                  >>и так как я ещё не встроил никакой системы выхода из
                  >>цикла for(), программа просто ждёт поступления новых сообщений.
                  >>Как встроить этот выход пока не решил, - может быть что-то подскажете?
                  >
                  >Зависит от того, какое условие выхода.

                  Условие выхода,- если отправитель заканчивает свой цикл раньше получателя и выходит из программы, получатель должен выйти из цикла for(). Количество шагов и у получателя и у отправителя я одинаковое установил. Соответственно, если некоторые сообщения пропали,- получатель зависает в цикле. Если я при этом данные пишу в мега-буффер, то они теряются, потому как переписывание в файл вставил только по окончании цикла for(). Приходится с Ctrl+C прерывать программу...
                  Поэтому хотел встроить выход из цикла с помощью таймера,который ждёт перед recvfrom допустим 5 секунд, а затем выводит из цикла.Так как сообщения приходят циклично, нормальная пауза составлять должна микро или миллисекунды. Но, как уже писал пока не разобрался с имплементацией этого решения. Может быть посоветуете что-то более простое.

                  >Посредством вывода на экран вы занимаете процессор отправителя "лишней" работой между отправкой
                  >пакетов, поэтому, возможно, количество отправленных пакетов/сек будет меньше, чем раньше, а
                  >значит меньше будет и потерянных.

                  Перепроверю сейчас с паузами вместо printf.

              • TCP/IP в режиме реального времени, !*! vic, 09:50 , 30-Авг-07 (14)
                • TCP/IP в режиме реального времени, !*! Gor, 11:23 , 30-Авг-07 (15)
                  >Есть такая мысль, берем программу типа сниффер, ставим на сбор входящего потока.
                  >
                  >Собрав часть потока, достаточную для анализа смотрим лог сниффера на предмет наличия
                  >потерь.
                  >Если сниффер ничего не потеряет, значит дело в программе принимающей пакеты. Иначе
                  >лечить отправителя понижая скорость передачи пакетов.

                  Проверил сниффером Варешарк. Все пакеты отсылаются, - вижу их все в сети.
                  При этом отправитель отсылал без пауз.

                  Значит проблема в принимающей стороне.
                  Попробовал увеличить буффер на приёме до 240 КБ(setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &n(ravnyi 240*1024),sizeof(n))
                  Не помогло.

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

                  что касается кода,- сейчас он выглядит иначе, так как связь идёт по удп.Привожу актуальный код и перепроверю,что я в нём не учёл с учётом Ваших советов.

                  Server:

                      for(i=10000; i<=99999; i++)
                       {    
                          char puffer_our_time[9];
                          len=sizeof(client_addr);
                              length = recvfrom(sock_fd, puffer_find_number_time,22, 0, (struct  sockaddr *) &client_addr,(socklen_t *) &len);
                          puffer_find_number_time[length]='\0';
                                  
                          gettimeofday( &tv, 0 );
                          actual_time = localtime( &(tv.tv_sec ) );
                          strftime( puffer_our_time, 9, "%H:%M:%S", localtime( &(tv.tv_sec ) ) );
                              if (length != 0)
                                {
                          printf("%d\t%s.%ld\t\t%s",i,puffer_our_time,i,puffer_our_time,tv.tv_usec,puffer_find_number_time);
                            }
                          else
                            {      printf("Connection closed by remote host.\n");
                                       break;
                            }
                       }

                  Client:
                      for(i=10000;i<=99999;i++)
                          {
                                  gettimeofday((struct timeval *) &tv, 0 );
                            actual_time = localtime( &(tv.tv_sec ) );
                            strftime(vorbuffer,9, "%H:%M:%S", localtime( &(tv.tv_sec ) ) );

                            length=sprintf(buffer,"%d\t%s.ld\n",i,vorbuffer, tv.tv_usec);

                          /*  printf("%d\t%s\n",i,buffer);*/
                          
                            err = sendto(sock_fd, buffer, length, 0, (struct sockaddr *) &server_addr,sizeof(server_addr));    
                            if(err==-1)
                              err_exit("send: send() failed");
                      /*    usleep(500);*/
                          }

                  • TCP/IP в режиме реального времени, !*! vic, 13:18 , 30-Авг-07 (16)
                    • TCP/IP в режиме реального времени, !*! Gor, 14:58 , 30-Авг-07 (17)
                      >> for(i=10000; i<=99999; i++)
                      >
                      >начальное значение сбивает с толку :)

                      Я это сделал, чтобы величина буффера не изменялась.
                      Таким образом на счётчик у меня всегда уходит 5 байт(с 10000-99000), иначе пришлосъ бы подстраиватъся с обоих сторон под увеличивающийся размер пересылаемой строчки. Красота выдачи значений в данный момент роли не играет.Понадобиться более длительное время работы программы,- изменю десqтки тысяч на сотни или миллионы, а заодно и размер буффера.

                      >Я же просил 400 капель, а тут 402 <c> :(
                      >проверку сразу после функции делать, и проверять на < 0 надо. И
                      >анализировать еще значения errno.
                      >man recv

                      Каюсь, Вы совершенно правы. Сейчас всё переделаю и добавлю проверку на -1.
                      Постараюсь не допускать таких глупых ошибок в будущем...




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

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