Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Неблокирующие борланд сокеты, Механизм работы 
:(
    Опции темы
Wolf
  Дата 22.3.2009, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 9.6.2006
Где: Нижневартовск

Репутация: нет
Всего: нет



Доброго времени суток!

При изготовлении клиет-серверного приложния на компонентах ServerSocket ClientSocket постоянно возникают проблемы. Возникают при интенсивном обмене данными между клиентами. Задача состоит в том, как бы принять пакет данных используя OnClientRead и OnRead и обработать его. И тут начинают твориться такие странности, что сложно даже понять - откуда исходит ошибка. Подскажите, какую модель ввода-вывода используют борландовские сокеты в неблокирующем режиме? И почему в неблокирующем режиме, обрабатывая всех клиентов в одном потоке функция OnClientRead может запуститься во время выполнения самой себя (судя по всему если от клиента приходит очередной пакет).

Вот код приёма пакета на сервере. Сначала в критической секции определяется клиент из списка. Структура клиента тоже прилагается. Приём первых 4 байтов, в которых указана длина пакета. Далее в 10 байтах название команды в протоколе, ну и данные далее.

Структура Client

Код

struct Client {
    char RemoteAddress[20];
    char Name[100];
    bool Auth;
    int AuthTimeOut;
    int Level;
    bool TimeOut;
    bool LockReadClient;

    TCustomWinSocket *Socket;
    TListItem *lvItem;
    _RTL_CRITICAL_SECTION IOCritical;
}    ;


Код приёма на сервере

Код

void __fastcall TfrmMain::ServerSocketClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
    EnterCriticalSection(&ClientsListChange);

    Client *CurClient;
    int ClientIndex;
    bool ClientExist = false;

    for (ClientIndex = 0; ClientIndex < ClientsList->Count; ClientIndex++) {
        CurClient = (Client *) ClientsList->Items[ClientIndex];

        if (strcmp(CurClient->RemoteAddress, Socket->RemoteAddress.c_str()) == 0) {
            ClientExist = true;
            break;
        }
    }

    LeaveCriticalSection(&ClientsListChange);

    if (ClientExist) {
        if (Socket->ReceiveLength() >= 4) {
            int ReciveBlockLength = 0;
            Socket->ReceiveBuf(&ReciveBlockLength, 4);

            if ((ReciveBlockLength <= 0) || (ReciveBlockLength > 1048576)) {
                CurClient->Socket->Close();
            }
            else {
                char *Buffer = new char [ReciveBlockLength];
                int Recived = 0;

                while (Recived != ReciveBlockLength) {
                    Recived += Socket->ReceiveBuf(&Buffer[Recived], ReciveBlockLength - Recived);
                }

                ChooseAction(Buffer, ClientIndex);
            }
        }
    }

}


Приблизительно тоже самое на клиенте только без определения того, кто отправил

Код

void __fastcall TfrmMain::ClientSocketRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
    if (Socket->ReceiveLength() >= 4) {
        int ReciveBlockLength = 0;
        Socket->ReceiveBuf(&ReciveBlockLength, 4);

        if ((ReciveBlockLength <= 0) || (ReciveBlockLength > 1048576)) {
            Socket->Close();
        }
        else {

            char *Buffer = new char [ReciveBlockLength];
            int Recived = 0;

            while (Recived != ReciveBlockLength) {
                Recived += Socket->ReceiveBuf(&Buffer[Recived], ReciveBlockLength - Recived);

                wsprintf(TEMP, "Получил блок: %d", Recived);
                Memo1->Lines->Add(TEMP);
            }

            ChooseAction(Buffer);
        }
    }
}


Кто сталкивался или знает как правильно принимать пакеты, подскажите пожалуйста. Бду крайне признателен.
PM MAIL ICQ   Вверх
Wolf
Дата 7.4.2009, 20:00 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 9.6.2006
Где: Нижневартовск

Репутация: нет
Всего: нет



В общем, почитал литературку. Кому интересно: компоненты TServerSocket & TClientSocket в неблокирующем режиме работают в модели перекрытого ввода-вывода используя для уведомления готовности чтения-записи функцию обратного вызова, которая запускается в главном потоке программы, при условии если поток Sleep. Тоесть гдето борландовцы вставили слип в цикле обработки сообщений. И в целом, это почти самое ужасное что я когда либо видел. Не используйте борланд компоненты TServerSocket & TClientSocket в неблокирующем режиме. Лучше вообще не используйте борланд сокеты.
PM MAIL ICQ   Вверх
dumb
Дата 8.4.2009, 04:03 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 32
Всего: 158



Цитата(Wolf @  7.4.2009,  20:00 Найти цитируемый пост)
общем, почитал литературку. Кому интересно: компоненты TServerSocket & TClientSocket в неблокирующем режиме работают в модели перекрытого ввода-вывода используя для уведомления готовности чтения-записи функцию обратного вызова, которая запускается в главном потоке программы, при условии если поток Sleep.
ссылку на литературу - в студию!

Цитата(Wolf @  7.4.2009,  20:00 Найти цитируемый пост)
Тоесть гдето борландовцы вставили слип в цикле обработки сообщений. И в целом, это почти самое ужасное что я когда либо видел.
так "гдето" или таки "видел"?

Цитата(Wolf @  7.4.2009,  20:00 Найти цитируемый пост)
Не используйте борланд компоненты TServerSocket & TClientSocket в неблокирующем режиме. Лучше вообще не используйте борланд сокеты.
может перед тем, как публиковать такие громкие лозунги, стоит немного разобраться в вопросе?

исходники вышеозначенных компонент лежат в папочке Source\vcl, немного почитав которые, становится очевидным, что компоненты TServerSocket & TClientSocket в неблокирующем режиме НЕ работают в модели перекрытого ввода-вывода.

а главная проблема в твоем коде - попытка чтения всех(еще не "приехавших") данных, вместо того, чтобы вычитать столько, сколько пришло - Socket->ReceiveLength().
PM MAIL   Вверх
Wolf
Дата 8.4.2009, 07:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 9.6.2006
Где: Нижневартовск

Репутация: нет
Всего: нет



dumb, Ну, я понимаю, что проще ответить неопределённо, чем ответить конкретно на вопросы. Если не перекрытый ввод-вывод, то каким образом запускается функция в главном потоке, причём прерывая выполнение потока? 

Я нашёл статью в инете, в которой был описан принцип действия перекрытого IO. Исходя из описанного я и сделал вывод. Громкие заявления сделаны после того, как я переписал всё на апи, у меня это отняло не много времени и я понял, что это не сложнее. Более того, отсутствуют абстракции от апи кода. Тоесть ты точно понимаешь, как и что у тебя работает. Там где тебе нужно, как нужно обрабатываются ошибки. Какие хочешь модели, сколько хочешь потоков в пуле.
Цитата

а главная проблема в твоем коде - попытка чтения всех(еще не "приехавших") данных, вместо того, чтобы вычитать столько, сколько пришло - Socket->ReceiveLength()


Если всё было бы просто, я бы не писал. Я в этом проблемы не вижу. Да и к тому же, всё это проверялось. Опять же неопределённый ответ... "Главная проблема.... а вообще проблем так много в твоём коде....".

Цитата

исходники вышеозначенных компонент лежат в папочке Source\vcl


Вот этого не знал. Я программирую на VC++ по этому не особо где что.

А вот ещё. Название файлика, пожалуйста  smile  в котором.
Цитата

немного почитав которые, становится очевидным

Если не затруднит, конечно.

Это сообщение отредактировал(а) Wolf - 8.4.2009, 07:11
PM MAIL ICQ   Вверх
mrbrooks
Дата 8.4.2009, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Цитата(Wolf @  8.4.2009,  07:02 Найти цитируемый пост)
Я программирую на VC++ 

Дык настоящий визуальщик пишет на голых сокетах   smile 

Цитата(Wolf @  8.4.2009,  07:02 Найти цитируемый пост)
А вот ещё. Название файлика, пожалуйста

Хочу предупредить - исходник написан на Паскале. Интерес не угас?  smile 

А вообще в Бормане, имхо, рулят Indy. Если уж что и копать, то именно их.
PM MAIL   Вверх
Wolf
Дата 8.4.2009, 08:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 9.6.2006
Где: Нижневартовск

Репутация: нет
Всего: нет



mrbrooks, 
Цитата

Дык настоящий визуальщик пишет на голых сокетах

Я уже переписал на голых сокетах  smile   Я ж написал вот
Цитата

...после того, как я переписал всё на апи, у меня это отняло не много времени и я понял, что это не сложнее. Более того, отсутствуют абстракции от апи кода. Тоесть ты точно понимаешь, как и что у тебя работает

Просто думал облегчить себе труд... Оказалось всё наоборот. Вообще сейчас в программе из VCL я оставил только интерфейс. И тут я ругался на этот ВЦЛ. Когда на апи писал потоки и функции обработки клиента. Оказалось, что так просто не изменить интерфейс из другого потока. Нужно придумывать аналог функции Synchronize(). А он реализован в VCL таким нелепым образом... Короче, и интерфейс и не интерфейс в следующий раз буду печатать, а не щёлкать  smile 
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0547 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.