Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.10.25;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.88 MB
Время: 0.024 c
2-1251725937
Rembo
2009-08-31 17:38
2009.10.25
IdHttp.Post мультистрочная переменная


9-1182962956
Dib@zol
2007-06-27 20:49
2009.10.25
Многоугольник


15-1250975984
Германн
2009-08-23 01:19
2009.10.25
Мини-опрос. Кому сколько ехать из дома до той конторы,


1-1220597243
Mephala
2008-09-05 10:47
2009.10.25
Какой выбрать разделитель при передаче параметров


10-1160553379
Alex_KV
2006-10-11 11:56
2009.10.25
Не паботает Invoke