Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Назад Сервер TCP/IP ... много серверов хороших и разных Вперед

Варианты серверов

Простой последовательный сервер

Это самая простая и понятная форма сервера: приняв запрос он его обрабатывает, и до завершения обработки недоступен для новых запросов. Такой сервер интересует нас как эталон для сравнения: он имеет минимальное время реакции, так как не затрачивается время на порождение каких-либо механизмов параллелизма. С другой стороны, такой сервер на практике может быть просто неинтересен, так как не позволяет обслуживать других клиентов до завершения текущего обслуживания. Смотрим код (файл ech0.cc) такого простейшего сервера (код ретранслирующей функции retrans(), единой для всех серверов, уже был показан в составе common.cc):

#include "common.h" 
// последовательный ретранслятор тестовых пакетов TCP 
int main( int argc, char *argv[] ) { 
   int ls = getsocket( SINGLE_PORT ), rs; 
   setv( argc, argv ); 
   while( true ) { 
      if( ( rs = accept( ls, NULL, NULL ) ) < 0 ) errx( "accept error" ); 
      retrans( rs ); 
      close( rs ); 
      if( debug ) cout < "*" < flush; 
   }; 
   exit( EXIT_SUCCESS ); 
}; 

Для оценки результатов будем выполнять все сервера на хосте локальной сети 192.168.1.5, а тестирующий клиент будем запускать с хоста 192.168.1.5. Что мы имеем в итоге? Вот результаты выполнения клиента с этим сервером:

- запуск сервера:

$ sudo nice -n19 ./ech0 
waiting on port 51000 ... 

- выполнение клиента:

$ ./cli -a 192.168.1.5 -p 51000 -n 20 
host: 192.168.1.5, TCP port = 51000, number of echoes = 20 
time of reply - Cycles [usec.] : 
181581378[59157]   479803[156] 465566[151] 464991[151] 425580[138] 
459931[149]	443785[144]	444532[144]	467360[152]	446407[145]
453376[147]	508208[165]	451375[147]	462139[150]	442612[144]
477986[155]	456573[148]	470822[153]	443624[144]	465233[151]

Хорошо видно выраженный эффект кэширования (первый запрос), причём выраженный как на стороне клиента, так и на стороне сервера. А в остальном — достаточно устойчивые значения с умеренно низкой дисперсией. В архиве проекта есть ещё один (echo01.cc), чуть модифицированный и более громоздкий, вариант этого же сервера, который дополнен хронометражем собственных затрат (от запроса до ответа):

#include "common.h" 
// последовательный ретранслятор тестовых пакетов TCP 
int main( int argc, char *argv[] ) { 
   int ls, rs, i = 0, cl = calibr( 10000 ); 
   cout < "wait ..." < flush; 
   uint64_t cps = proc_hz(); // cycles per sec. 
   cout < '\r'; 
   ls = getsocket( SINGLE_PORT ); 
   setv( argc, argv ); 
   while( true ) { 
      if( ( rs = accept( ls, NULL, NULL ) ) < 0 ) errx( "accept error" ); 
      uint64_t cycle = rdtsc(); 
      retrans( rs ); 
      cycle = rdtsc() - cycle; 
      cycle -= cl; 
      close( rs ); 
      cout < cycle < "[" < cycle * 1000000 / cps < "]";   // sec. / 10E6 
      if( i++ % 5 == 4 ) cout < endl; else cout < '\t'; cout < flush; 
   }; 
   exit( EXIT_SUCCESS ); 
}; 

Вот как это происходит:

$ sudo nice -n19 ./ech01 
waiting on port 51000 ... 
94779209[57010]	47509[28]	30759[18]	39479[23]	37919[22]
36869[22]	35249[21]	29879[17]	29099[17]	29409[17]
28059[16]	38139[22]	38909[23]	28749[17]	27439[16]
28359[17]	28059[16]	28229[16]	27609[16]	38399[23]
$ ./cli -a 192.168.1.5 -p 51000 -n 20 
host: 192.168.1.5, TCP port = 51000, number of echoes = 20 
time of reply - Cycles [usec.] : 
175292660[57109]	458045[149]	471339[153]	412701[134]	415955[135]
388539[126]	397957[129]	453100[147]	453066[147]	518639[168]
445648[145]	454365[148]	409400[133]	461564[150]	444257[144]
451605[147]	427305[139]	454503[148]	453847[147]	404167[131]

В данном случае сравнение чисел процессорных тактов бессмысленно, потому как они относятся к разным процессорам (клиента и сервера), а вот значения в микросекундах позволяют убедиться, что собственно на ретрансляцию в последовательном сервере затрачивается не более 10% общего времени прохождения запроса и ответа. Здесь это всё наглядно и просто, но такой вариант сервера позволяет анализировать выполнение клиента и сервера на едином хосте через петлевой интерфейс (127.0.0.1), когда клиент и сервер разделяют общее время процессора, и анализ происходящего становится много сложнее.


Назад Сервер TCP/IP ... много серверов хороших и разных Вперед