-
RelleH (16.12.11 09:06) [0]Добрый день.
Нуждаюсь в совете или наставлении как правильно реализовать сервер.
Задача сервера заключается в предоставлении информации по запросу клиента, также изменение данных на сервере по запросу клиента. (клиенты-Gps навигаторы с встроенным GSM шлюзом, Интернет -GPRS). ПО сервера пишется на CodeGear Delphi 2009 используется компонент Indy TidCmdTCPServer под платформу Win7(32). Сторона клиента пишется в среде Lazarus под WinCe (arm).
Перед началом разработки была найдена и прочитана книга Анатолия Подгорецкого "Глубины Indy". Опыта в разработке подобных систем нет.
Очень хочется сделать все грамотно и правильно с самого начала.
Сервер взаимодействует с БД FireBird 2.1, на данном этапе сервер по запросу со стороны клиента, выдает прочитанную в базе информацию. Информация в базу поступает непрерывно (работают люди забивают заказы полученные по телефону от клиентов, имеется очередь водителей по каждому району города).
Приведу пример общения клиента с сервером.
>>>200 Welcome
<<<@2@
>>>200 @2@<vBKNTLTQa7zhDNIUTMfkQV19L4ylwpHyfQ7q20JgaZ7rPFkGx3zAWPwCE4X6WRGZOBHd8LmgcbNF U+rNT1WzkDoh1jUQ8/H7Kjjn6+TzN/5/hMhisjKTZ4epiqmUpUAzBTFzkx8YFUV0UJO+rwer4aP6gv6JCtgiXuwe66U18xSSslgJ3DBPkTA6SBPDFD2AKC>(6)[213]
CRC ok...16.12.2011 6:15:06
<<<@1@
>>>200 @1@<0641000073002110300450110031065002203900250850014101001205900050451001084003 51200004019002001000110880002013001009200150080003>(18)[146]
CRC ok...16.12.2011 6:15:07
>>>200 @3@0
<<< quit
>>>200 Good Byu!
Тут @1@- Запрос информации расположения водителей по городу
@2@- Запрос у сервера информации о текущих заказах
@3@- Запрос на отклик сервера(проверяю наличие связи, отправляю с интервалом в 20 сек.)
Планируется подключение до 30-100 клиентов.
Сейчас реализовано следующим образом.
Сервер по таймеру с интервалом в 5 секунд выполняет хранимую процедуру БД FireBird которая формирует две строки:
1- Заказы
2- очередь водителей
Эти значения я записываю в глобальную переменную zakazi,ochered типа String;
procedure TForm1.TCPCommandHandlers1Command(ASender: TIdCommand);
begin
Asender.reply.text.text:='@1@'+ochered;
end;
procedure TForm1.TCPCommandHandlers2Command(ASender: TIdCommand);
begin
ASender.Context.Connection.Socket.DefStringEncoding:=enUTF8;
Asender.Reply.Text.Text:='@2@'+zakazi;
end;
procedure TForm1.TCPCommandHandlers3Command(ASender: TIdCommand);
begin
if ASender.Params.Count<>0 then
Asender.reply.text.text:='@3@'+ASender.Params[0];
end;
Клиент что бы видеть актуальную информацию по таймеру с интервалом в5 секунд запрашивает обновление данных из базы на сервере. (@1@,@2@).
procedure TForm1.Online_btnClick(Sender: TObject);
begin
if fnet.connected then
begin
Online_btn.Caption:='Подключиться';
Memo1.Lines.Add('<<< quit');
fnet.SendMessage('quit'+#10)
end
else
begin
fnet.Connect(server_ip,server_port);
if fnet.Connected=true then
Online_btn.Caption:='Отключиться';
end;
end;
procedure TForm1.TCPReceive(aSocket: TLSocket);
var
s: string;
begin
if aSocket.GetMessage(s) > 0 then
begin
Memo1.Append('>>>'+s);
Memo1.SelStart := Length(Memo1.Lines.Text);
if pos ('@1@',s)<>0 then Update_1(s); //Процедура расставляет водителей на компоненте stringGrid согласно купленным билетам
if pos ('@2@',s)<>0 then Update_2(s); //Расшифровывает и загоняет в ListBox полученные данные
if pos ('200 Good Byu!',s)<>0 then
TCP_Disconnect(true);
end;
function TCP_Disconnect(dlg:boolean):boolean;
Begin
result:=true;
Form1.FNet.Disconnect;
form1.orderlist.color:=$007E7E7E;
form1.Online_btn.Caption:='Подключиться';
form1.Memo1.Lines.Add('Клиент disconnect');
online:=false;
if dlg = true then if MessageDlg('Завершить работу?',mtInformation, mbOKCancel, 0) = 1 then
Form1.close;
end;
end;
Вообщем функций конечно - же будет больше, данные хотелось бы отправлять компактнее и экономнее, так как связь не стабильная.(как правило слабые антенны GSM модулей в навигаторах и плохое покрытие).
Чего бы хотелось...
1) Что бы сервер ждал события из базы и лишь тогда формировал пакет для отправки клиентам, а не перечитывал одни и те же данные по таймеру. (с этим не сложно)
2) Как только в базе обнаружились свежие данные формировать пакет и отправлять его всем клиентам.
Это для того, что бы клиенты не получали груды им ненужных пакетов. Так как иногда в часы пик информация обновляется часто а например ночью интенсивность обмена сильно снижается. Нет смысла дергать сервер запросами каждые 5 секунд или это нормально?
3) Интересно правильно ли выбран изначально TidCmdTCPServer?
4)Что лучше в моей ситуации подключатся к серверу, получать данные и сразу отключатся или подключатся и держать сеанс до последнего.
5) Какими методами изоляции потока порекомендуете пользоваться в процессе записи данных в БД.
Хотелось бы услышать ваши советы, замечания, критику и т.д.
Если кто подскажет литературу поделится примером, буду признателен.
Заранее спасибо, с уважением Андрей. -
Медвежонок Пятачок © (16.12.11 09:39) [1]Чего бы хотелось...
1) Что бы сервер ждал события из базы и лишь тогда формировал пакет для отправки клиентам, а не перечитывал одни и те же данные по таймеру. (с этим не сложно)
не надо ждать события "базы". надо реагировать на поступивший запрос клиента
2) Как только в базе обнаружились свежие данные формировать пакет и отправлять его всем клиентам.
не надо.
причин несколько.
так как это gprs, то значит клиент на натом. а значит сервер не может инициировать соединение с клиентом. а это значит, что клиент должен постоянно опрашивать сервер иначе сервер не сможет "как бы по своей инициативе" отправить всем клиентам данные.
но ты же сам говоришь, что инет там фиговатый.
в общем все у тебя не так. и все неправильно -
Медвежонок Пятачок © (16.12.11 09:40) [2]ну и в качестве сервера я бы не стал брать самопальный делфийский сервер.
-
Медвежонок Пятачок © (16.12.11 09:41) [3]и формат данных протокола я бы не стал такой брать.
-
RelleH (16.12.11 14:22) [4]Добрый день
> в общем все у тебя не так. и все неправильно
Если не сложно, можно поподробнее.
Что именно у меня не правильно?
На текущий момент клиент сам опрашивает сервер.
Мой клиент подключается, отправляет запрос, получает результат, проверяет состояние связи и корректно отключается.
Или я неправильно исполняю?
> ну и в качестве сервера я бы не стал брать самопальный делфийский
> сервер
В каком направлении смотреть?
> и формат данных протокола я бы не стал такой брать.
Какой бы вы посоветовали?
Спасибо -
Медвежонок Пятачок © (16.12.11 14:46) [5]все что ты сказал сейчас не соответствует тому что ты сказал вначале.
вначале было сказано, что сервер что-то там шуршит в базе по таймеру.
и было сказано, что сервер сам внезапно может захотеть что-то там отправить всем клиентам -
RelleH (16.12.11 15:42) [6]Спасибо за ответ.
Сервер я реализовал по образу и подобию примера сервера из книги Анатолия Подгорецкого "Глубины Indy". Там действительно вся инициатива исходит от клиента.
А главная проблема в том что пример приведенный там как и все примеры очень простой с точки зрения реализации и я не знаю как обстоит дело на самом деле на подобных серьезных серверах.
Отталкиваясь от информации предоставленной вами мне теперь становится ясно, что сервер не должен ничего предлагать клиентам, они сами все попросят, а он обработает и ответит.
По поводу того , почему у меня сервер по таймеру читает данные из БД. Попытаюсь объяснить.
Предположим что у меня в базе в течении 4 часов не изменяются данные, для примера пусть под данными имеется ввиду строка "123456789". А всем клиентам, подключенным к серверу необходимо знать когда эта строка изменится на строку "1234567890". Для этого они каждые 5 секунд отправляют запрос на сервер. В течении 5 секунд таких запросов на сервер приходит 100(при условии что у меня 100 активных соединений).
За эти 5 секунд Сервер производит 100 запросов(чтения) персонально для каждого клиента из базы данных.
И так в течении 4 часов. Это около 288 000 запросов.
А данные совсем не изменялись.
Вот отсюда и мой вопрос, не проще ли что бы сервер обнаружив изменение в базе данных(Firebird 2.1 отправляет событие на порт сервера), отправил данные всего 1 раз за весь этот час, всем подключенным клиентам. Экономия трафика, как мне кажется присутствует, - меньшая нагрузка на сервер.
Не подключенные или отключенные клиенты нам не надо, они сами при потере связи установят соединение и запросят при первом запуске "не пришло ли чего нового для них", сервер их не ищет.
Или так не делается, тогда как делается в серьезных серверах? Мне даже код не надо, мне бы понять логику. -
Медвежонок Пятачок © (16.12.11 19:03) [7]это все оптимизация плеча "сервер приложений - sql сервер".
и если его даже вусмерть заоптимизировать, то это все равно никак не скажется на плече "сервер приложений-удаленный клиент". -
Иван Сараев (18.11.12 18:45) [8]Блин точно такая ж проблема. Из за постоянных опросов сервера на наличие новых сообщений идет не хилый трафик да и сервер грузят эти сообщения мне кажется
-
Иван Сараев (18.11.12 18:46) [9]Удалено модератором
-
Anatoly Podgoretsky © (18.11.12 19:51) [10]
> RelleH (16.12.11 15:42) [6]
Есть два подхода
1. Всегда отвечать запрошеннвми данными.
2. Посылать данные только если они изменились, иначе сигнал что новых данных нет. Может резко сократить трафик. -
Иван Сараев (18.11.12 19:55) [11]Так я итак использую второй подход.. У меня не каждый раз грузятся новые данные а лишь узнается есть ли они вообще эти новые данные и лишь потом грузятся. Тем не менее все равно трафик
-
Cobalt © (20.11.12 09:38) [12]Ну, давай, рассказывай, что передаешь, какой состав трафика, какой процентный состав.