Использование SOCK_DGRAM
для UDP
сокетов
Все пакеты имеют длину 22 bytes
(т. Е. 64 including headers
)
client.c
...
no_of_packets--;
sprintf(buf, "#:!0 rem");
sprintf(buf, format , buf);
sprintf(buf_aux, "#: 0 rem");
sprintf(buf_aux, format , buf_aux);
buf[MAX_LINE-1] = '\0';
buf_aux[MAX_LINE-1] = '\0';
len = strlen(buf) + 1;
send(s, buf, len, 0);
while (no_of_packets-- > 1) {
nanosleep(&T, NULL);
send(s, buf, len, 0);
}
send(s, buf_aux, len, 0);
server.c
...
while(1) {
if (len = recv(s, buf, sizeof(buf), 0)){
// do nothing
}
}
Когда я открываю Wireshark
, чтобы увидеть среднюю задержку между отправляемыми пакетами,
я вижу следующее:
МИН [задержка 118]: 0,000 006 795 с => 6 мкс
МАКС. задержка: 0,000 260 952 с => 260 мкс
Но я хочу отправлять пакеты каждые 512 нсек (т. Е. 0,512 мкс).
Как можно достичь этой скорости?
Проблема с наносном состоит в том, что он включает довольно значительные издержки. Пользователи склонны ожидать точные задержки вниз с очень низкими значениями, который не действительно практичен для ЦП, приводящего к стандартной программе сна. Ожидание - это:
actual delay = nanosleep(requested delay)
тогда как, в действительности пользователи получают это:
actual delay = nanosleep(requested delay) + the fixed overheads.
На моем тестовом компьютере, с принудительной привязкой ЦП (для удаления эффектов планировщика) и набор регулятора частотного масштабирования ЦП к производительности фиксированные издержки составляют 52 микросекунды.
Возможное решение для Вашей проблемы состоит в том, чтобы заменить вызов, чтобы наноспать с циклом задержки. Затем ЦП не уступил бы, войдя неактивный, ни подвергся бы издержкам вызова операционной системы. Конечно, цикл задержки может быть трудно калибровать для фактического получения желаемой задержки. Я сделал две программы, один наносон использования и одно использование цикла задержки для демонстрации. Для создания других издержек незначительными, сон и циклы задержки выполняются очень много раз в течение каждого раза и печатают вызовы типа:
Для ссылки программы использовали:
версия наносна:
/*****************************************************************************
*
* test_slp2.c 2019.09.18 Smythies
* Create data to determine the lower limit of nanosleep.
*
* test_slp.cpp 2017.11.25 Smythies
* Of course, none of this stuff works the way it used to.
*
* test_slp.cpp 2012.01.24 Smythies
* I need to be able to yeild (sleep), but for less than a second.
* Experiment with nanosleep and usleep functions.
*
*****************************************************************************/
// prevent warning about nanosleep
#define _POSIX_C_SOURCE 199309L
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define CR 13
unsigned long long stamp(void){
struct timeval tv;
gettimeofday(&tv, NULL);
return (unsigned long long)tv.tv_sec * 1000000 + tv.tv_usec;
} /* endprocedure */
int main(){
unsigned long long start, now;
long i, j, k;
int ns;
struct timespec time;
time.tv_sec = 0;
start = stamp();
for(ns = 500; ns < 100000; ns = ns + 500){
for(j = 0; j < 100000; j++){
time.tv_nsec = ns;
nanosleep(&time, &time);
} /* endfor */
now = stamp();
printf("%d %llu\n", ns, (now - start));
start = now;
} /* endfor */
return(0);
}
И версия цикла задержки, включая сырую калибровку, которую показывает график, не является большой:
/*****************************************************************************
*
* test_slp3.c 2019.09.18 Smythies
* Now, do the same as test_slp2, but use a waste time loop instead of
nanosleep.
*
* test_slp2.c 2019.09.18 Smythies
* Create data to determine the lower limit of nanosleep.
*
* test_slp.cpp 2017.11.25 Smythies
* Of course, none of this stuff works the way it used to.
*
* test_slp.cpp 2012.01.24 Smythies
* I need to be able to yeild (sleep), but for less than a second.
* Experiment with nanosleep and usleep functions.
*
*****************************************************************************/
// prevent warning about nanosleep
#define _POSIX_C_SOURCE 199309L
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
/* for my test computer */
#define CALIBRATION 26
unsigned long long stamp(void){
struct timeval tv;
gettimeofday(&tv, NULL);
return (unsigned long long)tv.tv_sec * 1000000 + tv.tv_usec;
} /* endprocedure */
int main(){
unsigned long long start, now;
long i, j, k, m, loops;
int ns;
struct timespec time;
time.tv_sec = 0;
start = stamp();
for(ns = 500; ns <= 10000; ns = ns + 100){
loops = ns * CALIBRATION / 50; /* will have rounding issues */
for(m = 0; m < 10000000; m++){ /* this is just to slow things down, so we can test */
for(j = 0; j < loops; j++){
k = j; /* make sure any compile optimizer doesn't take out the loop */
} /* endfor */
} /* endfor */
now = stamp();
printf("%d %llu\n", ns, (now - start));
start = now;
} /* endfor */
return(0);
}
Ожидаемый вопрос: Почему никакие gettimeofday не дрожат в тесте абонентского шлейфа задержки, когда Вы (I) утверждаете, что это - причина дрожания в версии наносна? Ответ: Возможно becuase метод цикла задержки работал за намного дольше на образец, чем версия наносна. Или, я был неправ.
Привязка ЦП была вызвана для этих тестов. т.е.:
time taskset -c 3 ./test_slp3
Я синхронизировал полный тест так же, как проверку работоспособности, поскольку сумма отдельных времен должна равняться полному времени. Они сделали.
Регулятор частотного масштабирования ЦП был установлен на производительность:
$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
performance
performance
performance
performance
performance
performance
performance
performance