На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

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

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

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

    в 3 строки, но корректно настроить работу сервера не удается. Пошел сначала простым и неправильным путём:
    1. ServerSocket в режиме stNonBlocking
    ExpandedWrap disabled
      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 строки от клиента, но этого, само собой, не достаточно. Вот

    код:
    ExpandedWrap disabled
      //описываем класс
      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, соединение соответственно не "самолёт"... Заранее спасибо!
      Цитата Marchelo2012 @
      То есть все сообщения принимаются, но принимаются они "урезанными".

      Они не "урезанные". Сообщение целиком не помещено в пакет. Всего лишь. А ты принял пакет и не проверив, все ли тебе передал клиент, пихаешь его в Мемо. :D Так, как ты сам уже понял - делать нельзя. Что бы решить такого рода проблему и добавочно избежать "склеивания" строк и помещал в самом начале передачи блока его размер. Сервер, скачав эти байты и поместив их в переменную, скажем Интегер, уже точно ЗНАЛ, сколько ему еще осталось принять. :D Это по первому варианту.
      По второму только одно - мдя....Смотри:
      Цитата Marchelo2012 @
      ExpandedWrap disabled
        procedure TServerThread.ClientExecute;
        var i:integer;
        begin
            Form1.Memo1.Lines.Insert(0,'> '+ClientSocket.ReceiveText);
      Так из ПОТОКА работать с визуальными компонентами не то, что нельзя.... :D У потока есть процедура синхронизации - вот ее и необходимо пользовать. Разумеется, это не отменяет сказанного выше, т.к. "урезание" и "склеивание" будет происходить и в этом случае. :D Так что... :-?
        Цитата Marchelo2012 @
        простым и неправильным путём:

        Ошибка. Этот путь как раз непростой, но самый правильный для сервера (тем паче с кол-вом клиентов > 20). Просто почитай про асинхронный режим работы - хотя бы статью Антона Григорьева "Сокеты в Delphi". Вкратце - в режиме non blocking всё управляется событиями: клиент подключился - событие, клиент отправил данные - событие. Причем событие чтения может приходить несколько раз, пока не будет переправлен весь пакет данных. Поэтому рецепт простой:
        1) Создать класс-наследник от TClientSocket с полем буфера, куда будут собираться прочитанные данные.
        2) По событию ClientRead считывать данные в буфер и проверять, всё ли сообщение принято (при этом должна быть какая-то сигнатура окончания сообщения - перевод строки, или нулевой символ, или что-то еще).
        3) Когда данные полностью приняты, обрабатывать сообщение, отвечать клиенту "ОК" и пр.
        1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0.0791 ]   [ 15 queries used ]   [ Generated: 24.10.26, 05:45 GMT ]