Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Интернет и сети
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 13.02.2013, 14:31
Marchelo2012 Marchelo2012 вне форума
Прохожий
 
Регистрация: 13.02.2013
Сообщения: 4
Репутация: 10
По умолчанию ServerSocket в режиме ThreadBlocking

Добрый день, уважаемые программисты! Опишу вкратце решаемую задачу.
Необходим сервер приема данных (текстовые сообщения в 15-20 строк). Данные отправляют клиенты (устройства, которые

связываются с сервером по каналу GPRS). Всего их 2000-2500 шт., каждый отправляет сообщение 1 раз в 5 минут,

соответственно на сервер примерно 5-20 обращений в секунду. Принятое сообщение необходимо поместить в Memo. Вроде бы задача

в 3 строки, но корректно настроить работу сервера не удается. Пошел сначала простым и неправильным путём:
1. ServerSocket в режиме stNonBlocking
Код:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    begin
      {От клиента получено сообщение - выводим его в Memo1}
      Memo2.Lines.Insert(0,'Message received from client');
      Memo1.Lines.Insert(0,'> '+Socket.ReceiveText);
      if RadioButton1.Checked then begin
      ServerSocket1.Socket.Connections[0].SendText('OK');
      ServerSocket1.Socket.Connections[0].Close;
      end;
    end;
В таком режиме при появлении события посылки сообщения от клиента, сообщение записывается в Memo. Но, естественно, новое

соединение появляется раньше, чем происходит запись принятого текста.
То есть все сообщения принимаются, но принимаются они "урезанными". Ах да, забыл написать, что клиенту после приема от него

сообщения надо отправить "OK", чтобы устройство знало, что пакет принят и можно отключаться.
2. Было принято решение использовать сервер (как вы уже догадались=)) в режиме stThreadBlocking. При небольшом количестве

клиентов все работает прекрасно (вообщем то как и первый вариант), но при количестве 2000-2500 клиентов сообщения в Memo

вообще пишутся пустыми, и только изредка там появляется 1-2 строки от клиента, но этого, само собой, не достаточно. Вот

код:
Код:
//описываем класс
type
    TServerThread = class(TServerClientThread)
    procedure ClientExecute; override;
  end;
//описываем процедуру, которая будет срабатывать при запуске "нити"
procedure TServerThread.ClientExecute;
var i:integer;
begin
    Form1.Memo1.Lines.Insert(0,'> '+ClientSocket.ReceiveText);
    ClientSocket.SendText('OK');
    ClientSocket.Close;
    Terminate;
end;
...
procedure TForm1.ServerSocket1GetThread(Sender: TObject;
      ClientSocket: TServerClientWinSocket;
      var SocketThread: TServerClientThread);
    begin
      Memo2.Lines.Insert(0,'Get Thread');
      //создаем экземпляр класса с приоритетом реального времени
      SocketThread:=TServerThread.Create(true, ClientSocket);
      SocketThread.Priority:=tpTimeCritical;
      SocketThread.Resume;
    end;
Подскажите, как модернизировать код, чтобы сервер справлялся с поставленной задачей? В процедуре

TServerThread.ClientExecute нужно что-то дописать, чтобы сервер ждал полного сообщения от клиента, а уже потом отсылал ему

"OK" и закрывал соединение. Финальная строка в тексте, полученном от клиента, всегда начинается с "REND"...

p.s. не забываем, что клиенты работают по gprs, соединение соответственно не "самолёт"... Заранее спасибо!
Ответить с цитированием
  #2  
Старый 13.02.2013, 14:59
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от Marchelo2012
(текстовые сообщения в 15-20 строк)
а 1 строка длинной 1048576 символа?)))

1. сообщение наверняка бьется на несколько. поэтому будут выводится части сообщений вперемешку от всех клиентов. т.е. нужно части сообщения группировать по клиентам и накапливать их перед выводом. и почему то ответ всегда идет только первому клиенту.

2. нельзя из потока непосредственно писать в VCL визуальные объекты. читаем про Synchronize.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #3  
Старый 13.02.2013, 15:36
Marchelo2012 Marchelo2012 вне форума
Прохожий
 
Регистрация: 13.02.2013
Сообщения: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
а 1 строка длинной 1048576 символа?)))
25-100 символ в среднем
Цитата:
Сообщение от NumLock
2. нельзя из потока непосредственно писать в VCL визуальные объекты. читаем про Synchronize.
Посмотрим, спасибо. Ну мне не важно куда писать по большому счету. Это первая стадия проекта. Просто решил посмотреть корректно ли будут приниматься сообщения от устройств, так как следующем шагом будет передача пакета в другой поток, где он будет парситься, а готовые значения укладываться в БД. Вот с парсинг и укладку почти дописал, а сервер приема корректный не могу организовать.
То есть мне надо понять, что мне добавить в код, чтобы в конкретном потоке принимался полный текст от устройства. Также пока не представляю как буду передавать принятый ПОЛНОСТЬЮ пакет в другой поток для парсинга.
Вообщем для начала надо разобраться с приемом данных, а потом уже идти далее.
Ответить с цитированием
  #4  
Старый 13.02.2013, 15:49
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от Marchelo2012
что мне добавить в код, чтобы в конкретном потоке принимался полный текст от устройства
для этого сервер должен знать какой объем данных передает ему клиент. либо какой-то признак окончания данных должен быть.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #5  
Старый 13.02.2013, 15:57
Marchelo2012 Marchelo2012 вне форума
Прохожий
 
Регистрация: 13.02.2013
Сообщения: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
для этого сервер должен знать какой объем данных передает ему клиент. либо какой-то признак окончания данных должен быть.
Да, такой признак имеется. Последняя строка начинается с $REND. Только я не пойму, как мне проверить ReceiveText на наличие REND? То есть мне надо запустить какой то бесконечный цикл, в котором части будут сцепляться между собой, а выход будет происходить по пришествию REND. Только как это сделать, что-то не догоняю.
Ответить с цитированием
  #6  
Старый 13.02.2013, 16:07
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

как уже написал выше, всегда нужно быть готовым к тому, что длинное сообщение, отправленное клиентом, может разбиться на несколько. т.е. одно сообщение закончиться на $RE, а следующее начаться на ND. выход для событийной модели: "склеивать" все сообщения по каждому клиенту и проверять его конец на $REND. но наверное это удобней делать на блокируемом сокете в потоке. проще организовать свой клиентский буфер.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #7  
Старый 13.02.2013, 16:11
Marchelo2012 Marchelo2012 вне форума
Прохожий
 
Регистрация: 13.02.2013
Сообщения: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
как уже написал выше, всегда нужно быть готовым к тому, что длинное сообщение, отправленное клиентом, может разбиться на несколько. т.е. одно сообщение закончиться на $RE, а следующее начаться на ND. выход для событийной модели: "склеивать" все сообщения по каждому клиенту и проверять его конец на $REND. но наверное это удобней делать на блокируемом сокете в потоке. проще организовать свой клиентский буфер.
И в итоге вопрос, как это сделать?
Ответить с цитированием
  #8  
Старый 14.02.2013, 15:36
ispovedn1k ispovedn1k вне форума
Прохожий
 
Регистрация: 20.12.2012
Сообщения: 2
Репутация: 10
По умолчанию

Тебе совершенно верно написали про Syncronize. Доступ и работа с VLC-объектами должны
происходить только в родительском потоке. Именно для этого и нужен вызов Syncronize.

Как я понимаю, ты используешь класс TServerSocket. На сколько я знаю, это абстрактный
класс и его не рекоммендуют использовать напрямую. Лучше объявить дочерний, и пользоваться
им. В нем же (в дочернем) можно объявить обработчики событий, и привязать их прямо в конструкторе.
Пригодятся обработчики таких событий как OnGetSocket и OnRead

OnGetSocket возникает перед создаем клиент-серверного socket'a вида TServerClientWinSocket
Именно через него идет чтение и отправка данных. Именно он участвует во всех других
событиях, как уникальный идентификатор подключенного клиента.
Я предлагаю сделать обработчик этого события и создавать не просто TServerClientWinSocket,
а сначала обявить некий дочерний от него класс (например TServerClientWinSocket_x) и
создавать его. Что это даст? Например в дочерний класс, можно добавить переменную, которая
будет собирать тебе строки от клиентов, пока не настанет время их вывести.
Обработчик может выглядеть так:
Код:
TServerSocket_x.OnGetSocket(Sender: TObject; _Socket: TSocket;
				var ClientSocket: TServerClientWinSocket);
begin
	// при создании клиентского сокета создаем экземпляр СВОЕГО сокета.
	ClientSocket := TServerClientWinSocket_x.Create(_Socket, self.Socket);
end;


OnRead - ну тут все ясно. Возникает при необходисмости читать данные. И если ты решил меня
послушаться, и создал особый клиент-серверный объект сокета, то это решит твою проблему
со сбором строк. Просто складываешь их в переменную, пока не дойдешь до конца. А если
пришел указатель на конец данных, отправляй их на вывод через вызов Syncronize.

Как-то так.

Надеюсь, мои объяснения были понятны и помогли хоть как-то разобраться и составить план
действий.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 00:36.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter