Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2009.10.25;
Скачать: [xml.tar.bz2];

Вниз

TspClient и TspServever   Найти похожие ветки 

 
kostyl_kostyl   (2009-08-12 12:38) [0]

Добрый день. Прошу показать пример обмена сообщениями сервера и клиента с помощью этих компонентов. У меня не выходит.
Я пишу:

procedure TForm1.TcpServer1Accept(Sender: TObject;
 ClientSocket: TCustomIpClient);
begin
 TcpServer1.Sendln("Ответ");
end;
//-----
 if TcpClient.Connect then
 begin
   TcpClient.Sendln("Запрос");
   Response := TcpClient.Receiveln;
   ShowMessage(Response);
 end
 else
   ShowMessage("Нет ответа");
 TcpClient.Disconnect;    

В лучшем случае  выдает пустую строку. В худшем зависает на Response := TcpClient.Receiveln;. Помогите разобраться.
Заранее благодарю.


 
Palladin ©   (2009-08-12 12:50) [1]


> TForm1.TcpServer1Accept

и чем же ты руководствовался при выборе события?


 
Сергей М. ©   (2009-08-12 12:54) [2]


> kostyl_kostyl


Снрвер призван обслуживать множество клиентов.

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

TcpServer1.Sendln("Ответ");

?


 
Сергей М. ©   (2009-08-12 12:56) [3]


> procedure TForm1.TcpServer1Accept(Sender: TObject;
>  ClientSocket: TCustomIpClient);


Если звезды на небе зажигают, значит они кому-то нужны, не так ли ?
Если так, то почему у тебя не возник вполне резонный интерес к этому параметру ?


 
Dennis I. Komarov ©   (2009-08-12 13:01) [4]


kostyl_kostyl   (12.08.09 12:38)  
> procedure TForm1.TcpServer1Accept(Sender: TObject;
>  ClientSocket: TCustomIpClient);



>    TcpClient.Sendln("Запрос");

И где оно обрабатывается?


 
kostyl_kostyl   (2009-08-12 13:02) [5]

А...
Переписал так:

procedure TForm1.TcpServer1Accept(Sender: TObject;
 ClientSocket: TCustomIpClient);
begin
 ClientSocket.Sendln("Ответ");
end;

Нет ответа. Наверно клиенту надо подождать как о или как?


 
Сергей М. ©   (2009-08-12 13:08) [6]


> Наверно клиенту надо подождать


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


 
kostyl_kostyl   (2009-08-12 13:10) [7]


> Вряд ли он чего-либо дождется

Если делаю так в сервере

ClientSocket.Sendln("Ответ");
Sleep(2000);

тогда получаю.
А как определить отправлен ли ответ?


 
Сергей М. ©   (2009-08-12 13:13) [8]


> как определить отправлен ли ответ?


Давай определимся - так ли уж нужно, чтобы соединение разрывалось по инициативе именно сервера ?


 
kostyl_kostyl   (2009-08-12 13:16) [9]

Нет его дело послать ответ. Дело клиента дождаться ответа, если нет ответа, то делать че-то дальше.


 
Сергей М. ©   (2009-08-12 13:20) [10]

В обработчике OnAccept следует организовать цикл вида:

пока соединение существует делать
начало
  дождаться и получить запрос
  обработать полученный запрос
  отправить ответ-результат обработки запроса
конец


 
kostyl_kostyl   (2009-08-12 13:27) [11]


procedure TForm1.TcpServer1Accept(Sender: TObject;
 ClientSocket: TCustomIpClient);
begin
 while ClientSocket.Connected do
 begin
   if ClientSocket.Receiveln <> "" then
   begin
     ClientSocket.Sendln("Ответ");
   end;  
 end;
end;

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


 
Palladin ©   (2009-08-12 13:29) [12]


> [10] Сергей М. ©   (12.08.09 13:20)

хм...

After the server socket accepts the connection, the client socket completes the connection, and an OnConnect event occurs for the client socket.

чего я не понимаю?


 
Сергей М. ©   (2009-08-12 13:37) [13]


> Так чтоли?


Ну да, примерно так.


> Если несколько серверов слушают один порт


Это еще умудриться надо, чтобы заставить несколько серверов слушать на одном и том же адресе:порту


 
Сергей М. ©   (2009-08-12 13:38) [14]


> Palladin ©   (12.08.09 13:29) [12]


Ты куда-то не туда смотришь..
У TTCPServer нет события OnConnect.


 
kostyl_kostyl   (2009-08-12 13:40) [15]


> Ну да, примерно так

А я вайлом не повешу сервер?


 
Palladin ©   (2009-08-12 13:41) [16]


> [14] Сергей М. ©   (12.08.09 13:38)

туда, это описание события TTCPServer.OnAccept, последнее предложение, и гласит оно, на сколько я понял, о том что соедиенение у клиента не установится пока на сервере не отработает OnAccept


 
Сергей М. ©   (2009-08-12 13:43) [17]


> Palladin ©   (12.08.09 13:41) [16]


А.. ну да ..

Ну дык а какое дело серверу до событий на стороне клиента ?


 
kostyl_kostyl   (2009-08-12 13:44) [18]


> пока на сервере не отработает OnAccept

Кстати да. Я это заметил когда писал туда ShowMessage...


 
Сергей М. ©   (2009-08-12 13:46) [19]


> я вайлом не повешу сервер?


Не повесишь.


 
Сергей М. ©   (2009-08-12 13:47) [20]


> писал туда ShowMessage


Нельзя туда писать ShowMessage при BlockMode = bmThreadblocking !


 
kostyl_kostyl   (2009-08-12 13:50) [21]


> Не повесишь.

Аргументы? У меня же клиентов много. Могут не достучаться наверно ж?


 
Palladin ©   (2009-08-12 14:12) [22]


>  [17] Сергей М. ©   (12.08.09 13:43)

ну тык он(сервер) посылает, то в OnAccept, а клиент то еще даже не в курсе что соединение установилось... куда там чего прийдет на клиенте...


 
Dennis I. Komarov ©   (2009-08-12 14:12) [23]


> if ClientSocket.Receiveln <> "" then

Вот сдесь, все что получил твой сервер кануло в небытие, или ему не важно что какой-то клиент там чего-то прислал?


> Аргументы? У меня же клиентов много. Могут не достучаться
> наверно ж?

А какие нужны? Напиши и посмотри если не веришь...


 
Сергей М. ©   (2009-08-12 14:15) [24]


> Аргументы?


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


 
Сергей М. ©   (2009-08-12 14:16) [25]


> У меня же клиентов много


Сколько конкретно ?)


 
kostyl_kostyl   (2009-08-12 14:25) [26]


> Сколько конкретно ?)

Десяток. Это я сказал, указывая что не один.

> Вот сдесь, все что получил твой сервер кануло в небытие

И что делать то? Как правильно?


 
Сергей М. ©   (2009-08-12 14:29) [27]


> Десяток


Десяток - это курам на смех.
Серьезные проблемы возникнут при тысяче-другой клиентов.


 
Dennis I. Komarov ©   (2009-08-12 14:32) [28]


> И что делать то? Как правильно?

Очевидно, что перед тем как сравнивать, надо сохранить куда-нить полученное...


 
kostyl_kostyl   (2009-08-12 14:36) [29]


> Dennis I. Komarov ©   (12.08.09 14:32) [28]

А.., типа Get чистит буфер?


 
Dennis I. Komarov ©   (2009-08-12 14:46) [30]


> А.., типа Get чистит буфер?

Кто, где, кого чистит?


 
kostyl_kostyl   (2009-08-12 14:49) [31]

Когда я делаю там if ClientSocket.Receiveln <> "" и условие выполняется у меня уже в ClientSocket.Receiveln ничего не будет?


 
Dennis I. Komarov ©   (2009-08-12 14:51) [32]

А как думаешь, что из себя есть ClientSocket.Receiveln?


 
Сергей М. ©   (2009-08-12 15:01) [33]


> уже в ClientSocket.Receiveln ничего не будет?
>


Да.
Все что на момент этого вызова находилось во внутреннем буфере принимаемых данных, ты этим вызовом оттуда вычерпал. И если нигде не сохранил, то навсегда потерял.


 
kostyl_kostyl   (2009-08-12 15:03) [34]


> А как думаешь, что из себя есть ClientSocket.Receiveln?

Пока склоняюсь к мнению что регистр проца. А вообще без понятия.


 
Сергей М. ©   (2009-08-12 15:15) [35]


> склоняюсь к мнению что регистр проца


Интересно, на чем основано такое мнение ?
Вероятно на том что в проце якобы есть какие-то там "регистры" какого-то там невероятно большого размера ?)


 
Dennis I. Komarov ©   (2009-08-12 15:21) [36]


> Пока склоняюсь к мнению что регистр проца.

Ёёёёёё... какие слова страшные %)

> А вообще без понятия.

А посмотреть не судьба?


 
kostyl_kostyl   (2009-08-12 15:21) [37]


> Вероятно на том что в проце якобы есть какие-то там "регистры"
> какого-то там невероятно большого размера ?)

Ну не знаю я. А мнение такое потому что я подумал  что там ссылка на порт лежит. А вроде когда порт читается  из него данные изчезают. Я видел схему когдато...


 
Dennis I. Komarov ©   (2009-08-12 15:23) [38]


> kostyl_kostyl   (12.08.09 15:21) [37]

Овсянка в голове, сэр...


 
Сергей М. ©   (2009-08-12 15:36) [39]


> там ссылка на порт лежит


"Там" - это где ?)


 
kostyl_kostyl   (2009-08-12 15:37) [40]


> Peek at the incoming data. The data is copied into the buffer but is not removed from the input queue


 
Dennis I. Komarov ©   (2009-08-12 15:42) [41]

"Ну и что это за народное творчество..." (С) Матроскин


 
kostyl_kostyl   (2009-08-12 15:51) [42]

так к чему мы пришли? я не понял...


 
Dennis I. Komarov ©   (2009-08-12 15:52) [43]

к [38]...


 
kostyl_kostyl   (2009-08-12 15:56) [44]

ой, могли бы и сказать, а то ломаетесь тут... А вообще спасибо всем кто помогал.


 
Сергей М. ©   (2009-08-12 16:01) [45]


> kostyl_kostyl   (12.08.09 15:37) [40]


Это откуда такое взялось ?

Цитирую фрагмент справки к методу TBaseSocket.ReceiveLn :

Reads delimited lines of data from the socket.

..
Description

Receiveln reads a delimited chunk of data from the socket.  The delimeter cannot be part of the character set.  Receiveln fills the buffer until it reaches the delimeter.


 
Dennis I. Komarov ©   (2009-08-12 16:02) [46]


> могли бы и сказать, а то ломаетесь тут...

Это лишено смысла...


 
Сергей М. ©   (2009-08-12 16:04) [47]


> а то ломаетесь тут


Ну зато ты, видимо, тверже дуба - не cломаешься своей головой подумать и выяснить)


 
kostyl_kostyl   (2009-08-12 16:05) [48]


> Сергей М. ©   (12.08.09 16:01) [45]

Я просто глубже полез...

Кстати, а если у меня сервер очень долго обрабатывает сообщение, он будет все это время "держать" клиента?


 
Сергей М. ©   (2009-08-12 16:20) [49]


> Я просто глубже полез


"Глубже" - это куда ?


> если у меня сервер очень долго обрабатывает сообщение, он
> будет все это время "держать" клиента?


Что значит "держать" ?
Клиент волен в любое время по своему желанию "уйти")


 
Dennis I. Komarov ©   (2009-08-12 16:27) [50]


> "Глубже" - это куда ?

В процессор...


 
kostyl_kostyl   (2009-08-12 16:27) [51]

Не допустим сервер получил запрос и ему минутку надо или больше чтото проделать прежде чем отправить ответ.
Ка должен вести себя клиент если от послал запрос и хочет его получить в течение 10 минут не более, при этом для пользователя клиента это все должно быть прозрачно.


 
Dennis I. Komarov ©   (2009-08-12 16:30) [52]


> хочет его получить в течение 10 минут не более

тогда ждать 10 и потом "уходить"...

> при этом для пользователя клиента это все должно быть прозрачно.

Это как? И он то как тут оказался?


 
kostyl_kostyl   (2009-08-12 16:31) [53]


> Dennis I. Komarov ©   (12.08.09 16:27) [50]

recv(FSocket, buf, bufsize, MSG_PEEK)


 
kostyl_kostyl   (2009-08-12 16:32) [54]


> Это как?

Ну пользователь же ждет пока приложение получит ответ.


 
Dennis I. Komarov ©   (2009-08-12 16:34) [55]


> kostyl_kostyl   (12.08.09 16:31) [53]

Что-то я не видел этого в твоем коде... А вообще генофонд большой, давай еще "глубже"


 
Dennis I. Komarov ©   (2009-08-12 16:37) [56]


> Ну пользователь же ждет пока приложение получит ответ.

Ну и в чем заключается прозрачность для него? И потом, ты сперва разберись с одним, а потом уже про пользователя вспомнать будешь, какую он музыку будет слушать, пока твой сервер надрывается...


 
Сергей М. ©   (2009-08-12 16:44) [57]


> Ка должен вести себя клиент если от послал запрос и хочет
> его получить в течение 10 минут не более


Он должен запустить тем или иным образом какой-либо 10-минутный таймер, по срабатыванию которого волен закрыть соединение по своей инициативе.


> для пользователя клиента это все должно быть прозрачно


Что значит "прозрачно" ?


> пользователь же ждет пока приложение получит ответ


Если ему больше нечем заняться, то да - пусть себе ждет.
Разве в этом есть нечто непотребное ?


 
Anatoly Podgoretsky ©   (2009-08-12 16:45) [58]

> kostyl_kostyl  (12.08.2009 16:32:54)  [54]

Ну это дело клиента ждать или нет.


 
kostyl_kostyl   (2009-08-12 16:58) [59]


> рабатыванию которого волен закрыть соединение по своей инициативе.

Так ему надо делать попытки чтения все 10 минут правильно?

> я не видел этого в твоем коде

а это не в моем коде...


 
Dennis I. Komarov ©   (2009-08-12 17:08) [60]


> Так ему надо делать попытки чтения все 10 минут правильно?

Да тех пор, пока не прочитает то что нужно или не отвалится по таймауту

> а это не в моем коде...

И какого оно тут оказалось тогда? Телепаторы тестируешь?


 
Сергей М. ©   (2009-08-12 17:10) [61]


> ему надо делать попытки чтения все 10 минут правильно?


Все зависит от режима BlockMode


 
kostyl_kostyl   (2009-08-12 17:15) [62]


> Dennis I. Komarov ©   (12.08.09 17:08) [60]

function TBaseSocket.PeekBuf(var Buf; BufSize: Integer): Integer;
begin
 Result := ErrorCheck(recv(FSocket, buf, bufsize, MSG_PEEK));
end;


> Все зависит от режима BlockMode

Как зависит?


 
Сергей М. ©   (2009-08-12 17:19) [63]


> Как зависит?


Алгоритмы "ожидания" и "попыток" существенно отличаются.
При bmNonBloking логика одна, а при bmBlocking иная.
Но ты до сих пор не сподобился уточнить используемый тобой режим, а это весьма важно, если хочешь дальнейшего детального обсуждения.


 
Dennis I. Komarov ©   (2009-08-12 17:23) [64]


> не сподобился уточнить используемый тобой режим

Как он его выберет, если он не знает разницу?


> kostyl_kostyl   (12.08.09 17:15) [62]

А чего не весь модуль то? Чего ты этим хочешь сказать? Зачем ты приводишь сдесь функции, которые ты  не используешь?


 
kostyl_kostyl   (2009-08-12 17:25) [65]

Дело в том что я и не знаю какой мне использовать. Я хочу отправить запрос и получить ответ тут же, потому что приложению для дальнейшей работы надо знать результат. Но сервер довольно долго обрабатывает запрос. Вот я из этого и исхожу.


 
Dennis I. Komarov ©   (2009-08-12 17:28) [66]


> kostyl_kostyl   (12.08.09 17:25) [65]

Самому не смешно?


 
Сергей М. ©   (2009-08-12 17:31) [67]


> не знаю какой мне использовать


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

Остановись пока на каком-либо одном и будем его рассматривать в лупу.

По умолчанию, если мне не изменяет память, устанавливается режим bmMonBlocking.


 
kostyl_kostyl   (2009-08-12 17:36) [68]

ну у меня сейчас установлен на клиенти bmBlocking, а не сервере bmThreadBlocking


 
Dennis I. Komarov ©   (2009-08-12 17:36) [69]


> Сергей М. ©   (12.08.09 17:31) [67]

Может лучше сперва озвучить задачу, для чего весь этот бред, а уже потом...


 
kostyl_kostyl   (2009-08-12 17:54) [70]

Задача озвучена в:

> kostyl_kostyl   (12.08.09 17:25) [65]

или надо еще подробнее?


 
Dennis I. Komarov ©   (2009-08-12 18:03) [71]

Ты его сам то читал?


 
kostyl_kostyl   (2009-08-12 18:05) [72]


> Ты его сам то читал?

Я вас не пойму, что вы хотите услышать от человека, который не знает механизма работы?


 
Dennis I. Komarov ©   (2009-08-12 18:09) [73]


> Я хочу отправить запрос и получить ответ тут же, потому
> что приложению для дальнейшей работы надо знать результат.
>  Но сервер довольно долго обрабатывает запрос.

Какой ты хочешь "тут же" получить ответ от сервера, если он будет готов через "довольно долго"?

Или совсем клиника, или я не знаю что это...


 
kostyl_kostyl   (2009-08-12 18:10) [74]

Это идеальный вариант. Дело в том что я не знаю как не заставлять приложение ждать ответа и выполнять другие функции.


 
Dennis I. Komarov ©   (2009-08-12 18:16) [75]

А [24] для кого написано? Для Гоголя?


 
kostyl_kostyl   (2009-08-12 18:33) [76]

Постараюсь лучше объяснить:
Вот у меня код обработки ответа:

1.  TcpClient.SendBuf(ClientRequest, 13);
2.  TcpClient.ReceiveBuf(ServerResponse, 268);
3.  TcpClient.Disconnect;
4.  ProcessServerResponse(ServerResponse);

Меня смущает что строки 1 и 2 выполняться в один момент и вижу два бока, когда либо клиент зависнет на строке 2 либо в строке 4 ServerResponse будет неверная информация, потому что сервер долго обрабатывает запрос.


 
kostyl_kostyl   (2009-08-12 20:02) [77]

Я не знаю как будет на самом деле, но знаю что сервер точно сформирует ответ. А вот когда это будет я без понятия, возможно я уже отконнекчусь и он не успеет передать данные. Значит мне надо подождать пока он это сделает, но вот ждать я не могу. Что делать? Может сделать обработку ответа в отдельном потоке, а по приходу ответа изменить какую то глобальную переменную и запусить ProcessServerResponse(ServerResponse)?


 
Сергей М. ©   (2009-08-12 20:22) [78]

А ты вообще в курсе, какой кодовый поток процесса твоего приложения ответственен за GUI ?


 
kostyl_kostyl   (2009-08-12 22:17) [79]

Если честно не в курсе


 
Сергей М. ©   (2009-08-13 08:13) [80]

В VCL-приложении - основной.
И он же, основной поток, у тебя вызывает метод ReceiveLn.
Пока метод не завершит выполнение, осн.поток не будет исполнять свои GUI-обязанности, что и создает иллюзию "подвисания".
Отсюда напрашивается решение: либо переносить работу с TTCPClient в доп.поток (он так же будет "зависать" на время вызова метода, но это не повлияет на работу осн.потока, ибо потоки исполняются "параллельно") либо переводить TTCPClient в режим bmNonBlocking, оставив работу с ним в осн.потоке.


 
kostyl_kostyl   (2009-08-13 10:18) [81]


> В VCL-приложении - основной.

Ну я так и думал в принципе. Вы хотите сказать, что в режима bmBlocking клиент будет ждать пока сервер не отправит ему данные? А как тогда он поймет, что все данные отправлены?


 
Сергей М. ©   (2009-08-13 10:31) [82]


> в режима bmBlocking клиент будет ждать пока сервер не отправит
> ему данные?


В этом режиме клиент вызвав ReceiveLn ждет до тех пор пока не получит строку целиком.
Если в ходе ожидания соединение будет разорвано (по инициативе сервера или по иной не зависящей от клиента причине), Receive-метод также завершит выполнение, но с возбуждением исключения.


> как тогда он поймет, что все данные отправлены?


Клиенту нет дела до отправки, он заинтересован в получении того что он ожидает.
Если клиент ожидал некую строку (по умолчанию концом строки клиент считает символы CRLF) и эта строка была успешно доставлена, то Receive-метод вернет управление, возвратив полученную строку.


 
kostyl_kostyl   (2009-08-13 10:50) [83]

Теперь все становится понятным. Спасибо за подробное объяснение.

> но с возбуждением исключения

А какой тип исключения не подскажите?
Постойте-ка, а как же тогда клиент может разорвать соединение если он ожидает конца строки в методе Receive?


 
Сергей М. ©   (2009-08-13 10:55) [84]


> как же тогда клиент может разорвать соединение если он ожидает
> конца строки в методе Receive?


Из другого потока закрыв хэндл сокета.
При этом блокирующее выполнение метода завершится с исключением.


 
Сергей М. ©   (2009-08-13 10:58) [85]


> какой тип исключения


Пардон, наврал я тебе.
Не исключение генерируется, а вызывается обработчик OnError, коему параметром передается конкретный код причины отказа. (см. WSAGetLastError)


 
kostyl_kostyl   (2009-08-13 11:11) [86]

Короче, как я понял самое простое решение сделать все в одном потоке в режиме клиента bmBlocking и наблюдать подвисания если сервер долго отвечает. Но как быть если сервер будет очень долго записывать данные, тоесть он не до конца заполнит строку и зависнет полностью. Тогда и приложение всё зависнет. Есть какие то таймауты или чтото такое?


 
Dennis I. Komarov ©   (2009-08-13 11:15) [87]


> Короче, как я понял самое простое решение сделать все в
> одном потоке в режиме клиента bmBlocking и наблюдать подвисания
> если сервер долго отвечает. Но как быть если сервер будет
> очень долго записывать данные, тоесть он не до конца заполнит
> строку и зависнет полностью. Тогда и приложение всё зависнет.
>  Есть какие то таймауты или чтото такое?

Вынеси в дополнительный поток...


 
kostyl_kostyl   (2009-08-13 11:21) [88]

Я наверно уже задолбал, но хочу спросит как будет вести себя клиент  в режиме bmNonBlocking ?
Заранее благодарю!


 
Сергей М. ©   (2009-08-13 11:31) [89]


> как я понял самое простое решение сделать все в одном потоке
> в режиме клиента bmBlocking и наблюдать подвисания если
> сервер долго отвечает


Неправильно ты понял.

Как ты будешь "наблюдать", если у тебя всего один поток (основной) и он занят ожиданием ?

Решением для одного потока (основного) будет переход к bmNonBlocking.


 
Сергей М. ©   (2009-08-13 11:59) [90]


> как будет вести себя клиент  в режиме bmNonBlocking ?


В этом режиме транспортные методы возвращают управление немедленно.

Пример для этого режима:
..

В обработчике OnError:

if SocketError <> WSAEWOULDBLOCK then TTCPClient(Sender).Disconnect;

...
ожидание и получение текстового сообщения от партнера-сервера, сервер в этом примере должен отправлять непустое сообщение, обязательно завершающееся CRLF:


ServerResponse := "";
while TCPClient.Connected and ServerResponse <> "" do begin
 ServerResponse := TCPClient.ReceveLn;
 Application.ProcessMessages;  // обработка потенциальных GUI-событий  
end;


 
kostyl_kostyl   (2009-08-13 12:14) [91]

Блин, все равно надо поток делать (а так не хочется еще и тут разбираться), но в bmNonBlocking можно хоть таймаут  сделать, как я понял... Какие то не удачные компоненты...


 
Сергей М. ©   (2009-08-13 12:28) [92]


> в bmNonBlocking можно хоть таймаут  сделать


Можно.
И в blocking тоже можно. Но при этом ты лишаешься преимущества использования функциональности метода ReceiveLn.


> Какие то не удачные компоненты


Нормальные компоненты.
Простые и понятные донельзя.
Может это у танцора проблемы ?)


 
kostyl_kostyl   (2009-08-13 15:35) [93]

Сделал вывод такой:
Снимаю блок чтобы никто не зависал
Стартую соединение
Посылаю данные
Запускаю отдельные поток
В цикле из 10 итераций со слипом в одну секунду пытаюсь принять данные.
Если принял отдаю их и как то убиваю соединение и поток. Если  по окончанию цикла убиваю соединение и поток и говорю что сервера нет.
Вопросы как убить поток из себя самого? Как понять что данные приняты? Не пропадут ли данные пока будет спать поток?


 
Сергей М. ©   (2009-08-13 15:43) [94]


> Запускаю отдельные поток


Нахрена он нужен, если ты "снял блок" ?)
В неблок.режтиме все этго расчудесно реализуется в одном-единственном основном потоке.


 
Dennis I. Komarov ©   (2009-08-13 15:59) [95]


> Сделал вывод такой:

А надо другой:
Сперва определиться какого рода информация должна приходить от сервера.
Дальше от этого пляшем:
Спроектировать протокол обмена
Реализовать сервер.
И только после этого уже заниматься клиентской стороной...


 
Anatoly Podgoretsky ©   (2009-08-13 16:06) [96]

> Сергей М.  (13.08.2009 15:43:34)  [94]

При том с диким количеством соединений.


 
Сергей М. ©   (2009-08-13 16:10) [97]

В обработчике OnTimer:

Timer.Enabled := False;
TimedOut := True;

В обработчике OnError:

if SocketError <> WSAEWOULDBLOCK then
 TTCPClient(Sender).Disconnect;


...
TCPClient.SendLn("Запрос к серверу");
Timer.Interval := 10000;
TimedOut := False;
Timer.Enabled := True;
ServerResponse := "";
while TCPClient.Connected and not TimedOut and (ServerResponse <> ")" do begin
ServerResponse := TCPClient.ReceveLn;
Application.ProcessMessages;  // обработка потенциальных GUI-событий  
end;
Timer.Enabled := False;
if TimedOut then
 ShowMessage("Прошло 10 минут, но ответ сервера в ожидаемом виде не получен")
else
 ShowMessage("Получен ответ сервера :"#10 + ServerResponse);



 
kostyl_kostyl   (2009-08-13 18:04) [98]

И что если вайл будет, например,  четыре минуты крутиться, то я смогу нажимать кнопки и делать чё захочу? Даже опять в это место смогу прийти?


 
Сергей М. ©   (2009-08-13 18:40) [99]

Угу.
Даже из собственных штанов за это время успеешь выпрыгнуть)


 
kostyl_kostyl   (2009-08-13 18:59) [100]

Как вы думаете, наверно я думаю что не успеет потому что не сильно улавливаю вообще суть событийного подхода и думаю что каждая следующая строка строго идет за предыдущей и ничего в этот момент больше не может выполняться? Верно?


 
Anatoly Podgoretsky ©   (2009-08-13 20:00) [101]

Неверно, это тупой блокирующий режим, удобен для последовательного выполнения команд, расплата блокирование потока.

Событийный (родной для Делфьи и Виндоус) когда управление передается соответствующему обрабчику при возникновение события. Порядок выполнения не определен, поток не блокируется, в состоянии обрабатывать до нескольких десятков тысяц соединений одновнеменно в одном потоке. Расплата более сложная нелинейная логика. Обычно требует построения машины состояний, что бы организовать последовательность выполнения, для распознования в каком состоянии находится соединение.


 
Сергей М. ©   (2009-08-13 20:07) [102]


> Anatoly Podgoretsky ©   (13.08.09 20:00) [101]
> Неверно, это тупой блокирующий режим


Вообще-то мы тут уже с [93] поста про неблок.режим долдоним


 
Сергей М. ©   (2009-08-13 20:21) [103]


> kostyl_kostyl   (13.08.09 18:59) [100]


Смотря что считать стоками.
Если строки искл-но твоего кода, то да - ты не улавливаешь.


 
kostyl_kostyl   (2009-08-13 21:06) [104]

Да, я совсем, аж стыдно стало, не понимал, да и сейчас особо не вкурю, что есть очень большая разница между последовательностью строк в коде, разделения его в отдельных модулях и действительной последовательности исполнения строк кода. Это всё PHP блин....


 
Сергей М. ©   (2009-08-13 21:11) [105]


> Это всё PHP блин
</>

Эт точно)

РНР - сплошной разврат, тотальное оболванивание и без того неокрепших умов)

Можно сказать - инструмент, позволяющий пирожнику, мало что смыслящему в сапогах, тачать эти самые сапоги не хуже сапожника)


 
kostyl_kostyl   (2009-08-13 21:28) [106]

Не хочется конечно разводить тут холивар, но PHP действительно очень опасный язык в плане тенденции "общего" заблуждения по поводу его простоты. Динамическая типизация, тесная связь с окружением и основы UNIX должны все время быть в кеше мозга, чего естественно многие новички да и старички не делают. Жаль, что я уже не застал время С/С++. Высокоуровневость упрощает жизнь, но ограничивает развитие. То же самое могу сказать и о Delphi. Репид девелопмент оболочка заставляет начинающего думать о Delphi также, как и о PHP, разве что не в такой степени. Но ведь она такая совсем не для этого. Ладно. Спасибо большое всем за подсказки.


 
Anatoly Podgoretsky ©   (2009-08-13 21:30) [107]

> Сергей М.  (13.08.2009 21:11:45)  [105]

Дельфи не хуже развращает.


 
Сергей М. ©   (2009-08-13 21:32) [108]


> kostyl_kostyl   (13.08.09 21:28) [106]


> PHP действительно очень опасный язык в плане тенденции "общего"
> заблуждения по поводу его простоты


Строго говоря, тоже самое можно сказать и о Делфи.
Но выбор так или иначе за тобой)


 
Сергей М. ©   (2009-08-13 21:38) [109]


> Anatoly Podgoretsky ©   (13.08.09 21:30) [107]


Ну тебе-то ведь хорошо известно, откуда растут ноги у дельфийского разврата)

Лозунг "Делфи раньше чем горошок" культивировался и культивируется и по сей день .. всякого рода архангельскими и иже с ними)


 
kostyl_kostyl   (2009-08-14 00:45) [110]

Да, я именно так и хотел это назвать - разврат. Всё, пошел писать статью в блоге...


 
Сергей М. ©   (2009-08-14 09:01) [111]


> пошел писать статью в блоге


Порочащую "честь и достоинство" Делфи ?)


 
kostyl_kostyl   (2009-08-14 10:19) [112]

Нет, призыв к "раскрытию глаз"


 
Сергей М. ©   (2009-08-14 11:33) [113]


> призыв к "раскрытию глаз"


Ну поделись уж, не томи, кому и на что намерен "раскрывать" ?)


 
kostyl_kostyl   (2009-08-14 11:59) [114]


> Ну поделись уж, не томи, кому и на что намерен "раскрывать"
> ?)

Я еще не написал. Только начал. Хочешь, как напишу и оформлю отпишу на мыло?
А, пока есть вопрос? Почему в режиме noBlocking клиент возвращает
connect = false?


 
Сергей М. ©   (2009-08-14 12:24) [115]


> Хочешь, как напишу и оформлю отпишу на мыло?


Не хочу)
Ты лучше сюда отпишись - не одному мне любопытно)


> Почему в режиме noBlocking клиент возвращает
> connect = false?
>


Потому что в неблок.режиме операция коннекта является асинхронной : вызов метода Connect запускает эту операцию и немедленно возвращает управление. О фактическом завершении операции (успешном или неуспешном) станет известно позже.


 
kostyl_kostyl   (2009-08-14 12:36) [116]


> станет известно позже.

Ага, я понял, например в ОтЕррор может стать известно.
> Ты лучше сюда отпишись - не одному мне любопытно

Ок, как будет готова, обязательно сюда отпишу.
ЗЫ: у меня маленькая посещаемость =)


 
Сергей М. ©   (2009-08-14 12:40) [117]


> например в ОтЕррор может стать известно


Угу.


> у меня маленькая


Не беда)
Тренируй ее, культивируй - и вырастет большая-пребольшая)


 
kostyl_kostyl   (2009-08-14 14:52) [118]

Я так понял, что мне еще надо добавить:

f (SocketError <> WSAEWOULDBLOCK) and
 (SocketError <> WSAENOTCONN)  then
TTCPClient(Sender).Disconnect;


 
kostyl_kostyl   (2009-08-14 15:05) [119]

или как сервер должен реагировать? Я посылаю запрос, на сервере генерируется акцепт и сервер зависает на РесивБуфер.


 
kostyl_kostyl   (2009-08-14 16:19) [120]

блин, асинхронные режим - жестокая штука, ни какой однозначности. Теперь сервер не ловит запросов...


 
kostyl_kostyl   (2009-08-14 16:33) [121]

а, я понял сервер ждет данных, которые отослали до соединения. Как узнать что соединение установлено? Если оно не установлено, то к примеру  по Сергей М. ©   (13.08.09 16:10) [97] в вайл не зайдет программа? Есть событие какое-то?


 
kostyl_kostyl   (2009-08-14 17:40) [122]

есть, OnError....


 
Anatoly Podgoretsky ©   (2009-08-14 17:45) [123]

OnAccept


 
kostyl_kostyl   (2009-08-14 17:51) [124]


> Anatoly Podgoretsky ©   (14.08.09 17:45) [123]
>
> OnAccept

ааа... Ну мне надо тоже учитывать таймут коннекта, поэтому я отсылаю запрос на коннект, а потом вхожу в цилк и в нем посылаю запрос; и если в OnError ошибка=WSAENOTCONN, кручусь дальше, пока таймаут не сработает или ошибки WSAENOTCONN не будет. Нормальны вариант?


 
Anatoly Podgoretsky ©   (2009-08-14 20:11) [125]

> kostyl_kostyl  (14.08.2009 17:51:04)  [124]

Вопрос был другой, а для этого вопроса OnError, но при нормальном коннекте OnError не будет. Механизм в сильном приближение такой

OnListen > OnAccept|OnError (выход) > работа с сокетом  > OnDisconnect

И про что ты сейчас говоришь про сервер или про клиента, я про сервер.


 
kostyl_kostyl   (2009-08-14 23:54) [126]

Ха. А я про клиент.


 
Сергей М. ©   (2009-08-15 01:00) [127]


> kostyl_kostyl   (14.08.09 14:52) [118]


А ты не пробовал справку почитать ?
В ней ВСЕ написано - какие коды отказов ждать от той или иной ф-ци при тех или иных условиях ..

У меня, знаешь ли, нет великого желания цитировать ее здесь, справку ту самую.


> асинхронные режим - жестокая штука


Да уж)

Эт тебе не Пых-Пых развратный: вызвал какую-нть хрень - и жди результата, бо обязательно тут же будет)


> Как узнать что соединение установлено?


Вызывай повторно Open.. И следи ВНИМАТЕЛЬНО за OnError и OnConnect.


 
Сергей М. ©   (2009-08-15 01:07) [128]


> если в OnError ошибка=WSAENOTCONN, кручусь дальше


Справка гласит:

For a nonblocking socket, until the connection attempt completes all subsequent calls to connect on the same socket will fail with the error code WSAEALREADY.

Зачем нести отсебячину ?


 
kostyl_kostyl   (2009-08-15 11:36) [129]

Спасибо.


 
kostyl_kostyl   (2009-08-17 11:04) [130]

Я так понял мне надо еще проверять WSAEWOULDBLOCK  кроме WSAEALREADY?


 
Сергей М. ©   (2009-08-17 11:07) [131]

Всенепременно)


 
kostyl_kostyl   (2009-08-17 11:23) [132]

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


 
Anatoly Podgoretsky ©   (2009-08-17 11:48) [133]

> kostyl_kostyl  (14.08.2009 17:51:04)  [124]

Это неверный алгоритм, протим принципов работы ассинхронных компонент, до Accept не надо ничего посылать, а то тебя быстро в хакеры зачислят файрволы и возможно на заметку возьмут администраторы.


 
Anatoly Podgoretsky ©   (2009-08-17 11:50) [134]

> kostyl_kostyl  (14.08.2009 17:51:04)  [124]

Ты похоже просто не понимаешь ни принципы работы ассинхронной работы и что важнее принципы работы серверов и клиентов через TCP/IP. Это протокол с акцептированием, без акцептирования рвутся только сетевые черви.


 
kostyl_kostyl   (2009-08-17 12:12) [135]

Да, я действительно не знаю принципов работы  серверов и клиентов через TCP/IP. Знаю там, запрос - ответ, и все. Это мне урок. Дык мне просто полсать запрос на OnConnect клиента и не париться с циклами этими? Или как?


 
Сергей М. ©   (2009-08-17 12:16) [136]


> не париться с циклами этими


Не париться при bmNonBlocking  не получится - пропотеть таки придется)


 
kostyl_kostyl   (2009-08-17 12:20) [137]

Так что мне делать?


 
Сергей М. ©   (2009-08-17 12:23) [138]


> что мне делать?


Что тебе не понятно ?


 
kostyl_kostyl   (2009-08-17 12:38) [139]

Мне все время выдается WSAEWOULDBLOCK и таймаут заканчивается. Если у клиента режим на блокирующий, то у сервера тоже должен быть не блокирующий? У меня стоит среадблокинг? Это как будет влиять на взаимодействие с клиентом, который находиться в режиме нотблокинг?


 
Сергей М. ©   (2009-08-17 12:49) [140]


> Мне все время выдается WSAEWOULDBLOCK


Показывай код..


> Если у клиента режим на блокирующий, то у сервера тоже должен
> быть не блокирующий?


Фиолетово.
Клиентам нет и не должно быть никакого дела до режимов серверных сокетов, равно как и наоборот.


> среадблокинг? Это как будет влиять на взаимодействие с клиентом,
>  который находиться в режиме нотблокинг?


Серверу до лампочки режимы клиентов. Его задача - вовремя и безотказно обслужить запросы своих клиентов. Как и в каком режиме это будет делать сервер - клиентам точно так же до лампочки.


 
kostyl_kostyl   (2009-08-17 12:58) [141]

Это запрос. Выполняется однажды в одной операции обращения к серверу. Таких операций может быть много.

 ConnectToServer := False;
 WasCanselErrors := False;
 If TcpClient.Connected then
   TcpClient.Disconnect;
 TcpClient.Connect;
 StartTryConnectTime := Now();
 while not ConnectToServer do
 begin
   Application.ProcessMessages;
   if ((Now - StartTryConnectTime) > 0.0005)
   or WasCanselErrors then
   begin
     Result := False; //нет соединения с сервером
     Exit;
   end;
   ConnectToServer := True;
   TcpClient.SendBuf(ServerRequest, 256);
 end;

OnError клиента:
 if (SocketError = WSAEALREADY)
 or (SocketError = WSAEWOULDBLOCK)
 or (SocketError = WSAENOTCONN)
 then //Если нет коннекта
 begin
   ConnectToServer := False;
 end;
 if (SocketError <> WSAEWOULDBLOCK)
 and (SocketError <> WSAEISCONN)  then
 begin
   TTCPClient(Sender).Disconnect;
   WasCanselErrors := True;
 end;


 
Сергей М. ©   (2009-08-17 16:48) [142]

type
 TTcpClientFriend = class(TTcpClient)
 protected
   function ErrorCheck(rc: Integer): Integer; override;
 end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 Memo.Clear;
end;

var
 ConnError: Boolean;
 ConnErrorCode: Cardinal;
 ResponseString: String;

procedure TForm1.Button6Click(Sender: TObject);
var
 TcpClient: TTcpClientFriend;
begin
 TcpClient := TTcpClientFriend.Create(nil);
 try
   TcpClient.OnError := TcpClientError;
   TcpClient.OnConnect := TcpClientConnect;
   TcpClient.RemoteHost := "ya.ru";
   TcpClient.RemotePort := "80";
   TcpClient.BlockMode := bmNonBlocking;
   ConnError := False;
   Timer.Interval := 5000;

   Timer.Enabled := True;
   while Timer.Enabled and not (TcpClient.Connected or Application.Terminated or ConnError) do begin
     TcpClient.Connect;
     Application.ProcessMessages;
   end;
   if not TcpClient.Connected then
     Exit;

   Timer.Enabled := True;
   while Timer.Enabled and not (Application.Terminated or ConnError) do begin
     if TcpClient.Sendln("запрос") <> SOCKET_ERROR then
       Break;
     Application.ProcessMessages;
   end;
   if Application.Terminated or ConnError then
     Exit;

   Timer.Enabled := True;
   while Timer.Enabled and not Application.Terminated and (ResponseString = "") do begin
     ResponseString := TcpClient.Receiveln("");
     if ConnError then
       Break;
     Application.ProcessMessages;
   end;
   Memo.Lines.Add(ResponseString);

 finally
   TcpClient.Free;
 end;
end;

procedure TForm1.TcpClientError(Sender: TObject; SocketError: Integer);
begin
 case SocketError of
   WSAEWOULDBLOCK, WSAEALREADY, WSAEINVAL:;
 else
   Timer.Enabled := False;
   ConnErrorCode := SocketError;
   ConnError := True;
 end;
end;

procedure TForm1.TcpClientConnect(Sender: TObject);
begin
 Timer.Enabled := False;
end;

procedure TForm1.TimerTimer(Sender: TObject);
begin
 Timer.Enabled := False;
end;

{ TTcpClientFriend }

function TTcpClientFriend.ErrorCheck(rc: Integer): Integer;
begin
 if (rc = SOCKET_ERROR) and (WSAGetLastError = WSAEISCONN) then
   Result := 0
 else
   Result := inherited ErrorCheck(rc);
end;


Для работы клиента в неблок.режиме проще будет отказаться от TTcpClient в пользу штатного TClientSocket или TCP-клиента в составе ICS.


 
kostyl_kostyl   (2009-08-17 17:56) [143]

Спасибо. Ну я почти так хотел сделать


 
Сергей М. ©   (2009-08-17 19:48) [144]

Почти как ?)


 
kostyl_kostyl   (2009-08-18 10:42) [145]

Ну в цикле коннекты делать... Только вот, что надо переопределить ErrorCheck я бы никогда не догадался.


 
Сергей М. ©   (2009-08-18 12:47) [146]


> Ну в цикле коннекты делать


Не только коннекты, но и приемы и передачи.


> надо переопределить ErrorCheck


Можно и не переопределять. Но тогда Connected = True ни в жисть не дождешься, хотя коннект и будет установлен)


 
kostyl_kostyl   (2009-08-19 10:39) [147]


> Но тогда Connected = True ни в жисть не дождешься, хотя
> коннект и будет установлен)

Ну я не знаю нюансов работы этих компонентов и не сильно понимаю строки
(rc = SOCKET_ERROR)


 
Сергей М. ©   (2009-08-19 10:45) [148]

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


 
Anatoly Podgoretsky ©   (2009-08-19 11:55) [149]

Без изучения основ ничего хорошего не будет, а с основами уже не важно какие компоненты или АПИ


 
kostyl_kostyl   (2009-08-20 10:22) [150]

А можете посоветовать хорошую книжку, но не сильно водяную по сетям?


 
Сергей М. ©   (2009-08-20 10:44) [151]

http://www.delphimaster.ru/books/978531800453/


 
kostyl_kostyl   (2009-08-20 13:25) [152]


> Сергей М. ©   (20.08.09 10:44) [151]

спасибо, уже качнул себе.


 
kostyl_kostyl   (2009-08-21 14:07) [153]


> Ты лучше сюда отпишись - не одному мне любопытно)

Пока что не получается, опыта маловато для такой статьи.
Могу предложить почитать другую http://itdumka.com.ua/index.php?cmd=shownode&node=5


 
Сергей М. ©   (2009-08-21 14:45) [154]


> почитать другую


"Много букаф, ниасилил"
)


 
kostyl_kostyl   (2009-08-21 16:39) [155]


> "Много букаф, ниасилил"

я думаю дописать продолжение по поводу "Как ограничить пагубное влияние `чужих` методов кодирования на свои", там, наверно, будет еще больше букаф...



Страницы: 1 2 3 4 вся ветка

Форум: "Начинающим";
Текущий архив: 2009.10.25;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.86 MB
Время: 0.048 c
15-1250886604
Юрий
2009-08-22 00:30
2009.10.25
С днем рождения ! 22 августа 2009 суббота


8-1198474587
ImA
2007-12-24 08:36
2009.10.25
Поворот объекта по окружности


4-1220075003
DAS
2008-08-30 09:43
2009.10.25
Как сохранить Html страницу в *.txt зная его URL


2-1251100957
@!!ex
2009-08-24 12:02
2009.10.25
Как проще всего сделать Wizard?


15-1250800206
Юрий
2009-08-21 00:30
2009.10.25
С днем рождения ! 21 августа 2009 пятница





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский