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

Вниз

Recv и синхронный режим   Найти похожие ветки 

 
Ivan K   (2004-06-14 15:09) [0]

Как узнать, пуст ли буфер? А то иначе при вызове Recv оно (в смысле Recv) ждет, пока в нем что-то будет и вешает прогу...


 
Verg ©   (2004-06-14 15:26) [1]

var
 bytes_in_buffer : integer;
................
 if ioctlsocket(socket, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR then
 begin
    bytes_in_buffer - содержит количество байтов в приемном буфере
                            сокета socket
 end;
...............


 
Ivan K   (2004-06-14 16:15) [2]

спасибо.


 
Ivan K   (2004-06-14 16:33) [3]

ой... сия конструкция мне ноль возвращает в bytes_in_buffer. хотя когда в тупую ставлю
  C := Recv(Cs, A, 1024, 0);
он возвращает мне данные..


 
Verg ©   (2004-06-14 18:58) [4]


>  C := Recv(Cs, A, 1024, 0);
> он возвращает мне данные..


Значит на момент вызова ioctlsocket данных еще не было, а на момент recv -  были. Вот и все.


 
Ivan K   (2004-06-15 23:24) [5]

хм.. Как же правильно "дождаться" того момента, чтобы точно знать, что данные на месте?
И еще...
C := Recv(Cs, A, 1024, 0) писалось не после, а вместо условия с ioctlsocket. Так почему в Recv данные дошли, а в Iocltsocket - нет?? /непонятненько%(


 
Digitman ©   (2004-06-16 08:12) [6]


> ждет, пока в нем что-то будет и вешает прогу


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


 
Verg ©   (2004-06-16 13:48) [7]


> Ivan K   (15.06.04 23:24) [5]


Покажи полный код участка приема. Как и где ты применяешь эти ф-ции.


 
Ivan K   (2004-06-16 16:04) [8]

var
Cs                     : TSocket;
C                      : integer;
S                      : string;
A                      : array[0..2048] of Char;
bytes_in_buffer        : integer;
begin
 ...
 S := "top "+ IntToStr(Num) + " 0"#13#10;
 StrPCopy(A, S);  // перевод строки в Char
 bytes_in_buffer := 0;
 Send(Cs, A, Length(S), 0);
 C := Recv(Cs, A, 1000, 0);
 if (C > 0) and (A[0] = "+") then
   if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR then
     C := Recv(Cs, A, bytes_in_buffer, 0);
 -  ваш совет
 if (C > 0) then
 begin
 ...
 end;


Если вместо жирного написать
     C := Recv(Cs, A, 1024, 0)
то буфер забивается своими 1024мя символами (или меньше, если меньше=) ).
Единственная проблема, что он числа 1024 может не хватить, а выделять больше тоже не хочется, ибо нефиг память переводить ;)


 
Digitman ©   (2004-06-16 16:46) [9]


> Send(Cs, A, Length(S), 0);


где анализ результата ?


> C := Recv(Cs, A, 1000, 0);


а это что такое ? почему именно 1000 ?

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


> ваш совет


до "совета" тут как до Китая еще ...
опиши свой прикладной протокол инф.обмена ..


 
Verg ©   (2004-06-16 18:38) [10]


> if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR
> then
>      C := Recv(Cs, A, bytes_in_buffer, 0);  -  ваш совет


Чего "ваш совет"? Не понял.


 
Verg ©   (2004-06-16 18:45) [11]

Еще раз сначала.
Ты спрашиваешь:

> Ivan K   (14.06.04 15:09)  
> Как узнать, пуст ли буфер? А то иначе при вызове Recv оно
> (в смысле Recv) ждет, пока в нем что-то будет и вешает прогу...


Я отвечаю.
Вот как узнать количество байтов в приемном буфере сокета:


>
>
> Verg ©   (14.06.04 15:26) [1]
> var
>  bytes_in_buffer : integer;
> ................
>  if ioctlsocket(socket, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR
> then
>  begin
>     bytes_in_buffer - содержит количество байтов в приемном
> буфере
>                             сокета socket
>  end;
> ...............


Какие "еще" советы нужны?
Если ты знаешь количество байтов в приемном буфере сокета, то пуст он или не пуст можно не очень сложно определить путем математического сравнения этого количества байтов (bytes_in_buffer) со специальной величиной, в народе прозванной НУЛЕМ. :))


 
Ivan K   (2004-06-17 01:04) [12]


> можно не очень сложно определить путем математического сравнения
> этого количества байтов (bytes_in_buffer) со специальной
> величиной, в народе прозванной НУЛЕМ


Дык в том-то и дело, что bytes_in_buffer = 0. А в буфере все же что-то ведь есть!

Просто после подсказки пользовать такую удобную функцию моя цель несколько изменилась:
Раз можно точно узнать, сколько точно байтов в буфере, то зачем считывать всё блоками и проверять на 0? Лучше сразу получить весь буфер целиком, что я и попытался проделать в вышеописанном коде.

/я наверное не могу точно сформулировать, что хочу и что получаю... всё больше путаюсь%)


 
Ivan K   (2004-06-17 01:16) [13]

2 Digitman


> > Send(Cs, A, Length(S), 0);
>
>
> где анализ результата ?

У Socket_ERROR код 0... Там чуть ниже условие С > 0
Если вы об этом...

> > C := Recv(Cs, A, 1000, 0);
>
>
> а это что такое ? почему именно 1000 ?

А почему бы нет? А сколько? Как узнать размер принятой информации? Про ioctlsocket узнал из этого топика, да и сним пока ничего не получилось... Затем и пишу сюда за помощью...

> ты же следом затираешь содержимое буфера А новыми принимаемыми
> данными, даже не удосужившись обработать уже принятые в
> буфер данные (кроме первого символа "плюс")


А там кроме первого знака "+" есть еще ОК#13#10. И всё. Остальное в след. запрос принимается. Хотя теперь есть сомнение, на хорошем канале в один буфер всё не сольется ли?..
Область для меня новая, а потому не всё могу объяснить...


> опиши свой прикладной протокол инф.обмена ..

эээ... опиши что?.. %)) /я не волшебник - я только учусь =)


 
Verg ©   (2004-06-17 01:37) [14]


> Дык в том-то и дело, что bytes_in_buffer = 0. А в буфере
> все же что-то ведь есть!


Я не вижу в твоем коде отражения твоего понимания. Т.е. - откуда ж такая уверенность,  что в буфере "что-то ведь" есть? :)
Про какой вообще тогда "буфер" идет речь? - Сформулируй.


> А там кроме первого знака "+" есть еще ОК#13#10. И всё.
> Остальное в след. запрос принимается. Хотя теперь есть сомнение,
> на хорошем канале в один буфер всё не сольется ли?..


/*
"Полная каша в голове" (С) Digitman
*/


:))


 
Ivan K   (2004-06-17 02:18) [15]

>Я не вижу в твоем коде отражения твоего понимания. Т.е. - откуда ж такая уверенность,  что в буфере "что-то ведь" есть? :)

постараюсь... %)

Если вместо
if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR then
    C := Recv(Cs, A, bytes_in_buffer, 0);

я пишу просто
C := Recv(Cs, A, 1024, 0);  
то в А записывается массив данных...
Это не показатель?

По поводу каши в голове... да, похоже у меня тоже заваривается...%))
Но от почтового сервера в ответ на top 1 0 (что и передается Send(Cs, A, Length(S), 0) ) приходит
+ОК#13#10
и позже заголовок письма... Я так понял, его надо считывать следующим Recv"ом...
Опять непонятно объяснил?%)


 
Digitman ©   (2004-06-17 09:22) [16]


> Ivan K   (17.06.04 01:16) [13]
> У Socket_ERROR код 0... Там чуть ниже условие С > 0
> Если вы об этом...


Нет, не об этом.
Какое отношение "чуть ниже условие С > 0" имеет к вызову ФУНКЦИИ (!!) Send() ? Ведь эта функция возвращает результат ! И этот результат отражает успешность или неуспешность выполнения ф-ции ..А ты его, этот результат, игнорируешь, вызывая ф-цию как процедуру и считая, очевидно, что send() всегда выполнится успешно ..


> эээ... опиши что?..


> от почтового сервера в ответ на top 1 0 (что и передается
> Send(Cs, A, Length(S), 0) ) приходит
> +ОК#13#10


это и есть фрагмент протокола инф.обмена между сервером и клиентом - в ответ на запрос предопределенного формата/содержания приходит ответ также предопределенного (для ДАННОГО запроса) формата/содержания


> Остальное в след. запрос принимается


да ничего подобного ! в ответ на "top 1 0" сервер не ждет, пока ты сподобишься прочитать "+OK", он посылает поточные данные, начинающиеся с "+OK"

затребовав для чтения при первом Recv() 1000 байт, ты можешь получить заранее неизвестное (в диапазоне от 0 до 1000) число инф.байт ответного потока .. среди полученных в этот момент байт может оказаться не только "+OK", но и некоторая часть данных, которые сервер немедленно посылает следом за "+OK"

теперь - по поводу ioctlsocket(socket, FIONREAD, bytes_in_buffer) ...

не обольщайся, что даже если в bytes_in_buffer будет возращено ненулевое значение, например bytes_in_buffer = 15, то последующим recv() ты прочитаешь ровно 15 байт - это вовсе не гарантируется ... в дан.случае bytes_in_buffer показывает тебе, к приему не более какого числа байт ты должен быть готов


 
Verg ©   (2004-06-17 11:01) [17]


> Если вместо
> if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR
> then
>     C := Recv(Cs, A, bytes_in_buffer, 0);
> я пишу просто
> C := Recv(Cs, A, 1024, 0);  
> то в А записывается массив данных...
> Это не показатель?


Показатель чего? Ты чего хочешь добиться-то?

> C := Recv(Cs, A, 1024, 0);  то в А записывается массив данных...
Конечно. recv-то c 1024 будет ждать, пока данные в сокете появятся, хоть сколько данных, хоть один байт.

По шагам:

if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR then

Теперь bytes_in_buffer содержит кол-во байтов, которе на данный момент принял сокет со времени последнего recv. Эта-то ф-ция ничего не ждет. Она немедленно возвращает запрошенную информацию о состоянии буфера приема.

if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR  then
begin
 if bytess_in_buffer > 0 then
   C := Recv(Cs, A, bytes_in_buffer, 0); // Тут понятно
 else
    // А тут что ты намерен делать? Что дальше-то?
end;


 
Rouse_ ©   (2004-06-17 12:22) [18]

FIONREAD

Use FIONREAD to determine the amount of data pending in the network"s input buffer that can be read from socket s. The argp parameter points to an unsigned long value in which ioctlsocket stores the result. If s is stream-oriented (for example, type SOCK_STREAM), FIONREAD returns the amount of data that can be read in a single call to the recv function; this might not be the same as the total amount of data queued on the socket. If s is message-oriented (for example, type SOCK_DGRAM), FIONREAD returns the size of the first datagram (message) queued on the socket.

+ а какой размер буффера ты выставил через SO_RCVBUF?


 
Григорьев Антон ©   (2004-06-17 12:53) [19]


> Rouse_ ©   (17.06.04 12:22) [18]


Откуда цитата? В той версии MSDN"а, которая есть у меня на дисках(Апрель 2001), написано другое:

Use to determine the amount of data pending in the network"s input buffer that can be read from socket s. The argp parameter points to an unsigned long value in which ioctlsocket stores the result. FIONREAD returns the amount of data that can be read in a single call to the recv function, which may not be the same as the total amount of data queued on the socket. If s is message oriented (for example, type SOCK_DGRAM), FIONREAD still returns the amount of pending data in the network buffer, however, the amount that can actually be read in a single call to the recv function is limited to the data size written in the send or sendto function call.

Проверил на http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/ioctlsocket_2.asp - написано то же самое. Похоже, у тебя устаревшая информация.


 
Digitman ©   (2004-06-17 13:16) [20]


> Григорьев Антон ©   (17.06.04 12:53) [19]


не в ту степь тебя понесло, даже если хэлп от борланда чем-то на 1-й взгляд не похож на соотв.справку из MSDN

речь в дан.случае идет о stream oriented sockets (SOCK_STREAM), а не о message oriented sockets (SOCK_DGRAM)

..which may not be the same as the total amount of data queued on the socket - вот именно об этом идет речь !


 
Григорьев Антон ©   (2004-06-17 13:27) [21]


> Digitman ©   (17.06.04 13:16) [20]


Сравни цитаты из поста Rouse_ [18]:


> If s is message-oriented (for example, type SOCK_DGRAM),
> FIONREAD returns the size of the first datagram (message)
> queued on the socket.


и из моего:


> If s is message oriented (for example, type SOCK_DGRAM),
> FIONREAD still returns the amount of pending data in the
> network buffer, however, the amount that can actually be
> read in a single call to the recv function is limited to
> the data size written in the send or sendto function call.


Ты согласен, что в них написано прямо противоположное? Я всего лишь хотел выяснить, откуда расхождение. И про SOCK_DGRAM не я начал, в [18] это уже есть.


 
Digitman ©   (2004-06-17 13:38) [22]


> Григорьев Антон ©   (17.06.04 13:27) [21]


в [18] жирным выделено важное замечание касаемое ИМЕННО stream-oriented sockets.. и речь здесь идет конкретно о stream-oriented sockets, а не о каких-то иных


 
Rouse_ ©   (2004-06-17 14:03) [23]

> [19] Григорьев Антон ©   (17.06.04 12:53)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcewinsk/html/_wcesdk_ioctlsocket.asp


 
Григорьев Антон ©   (2004-06-17 15:03) [24]


> Digitman ©   (17.06.04 13:38) [22]
>
> > Григорьев Антон ©   (17.06.04 13:27) [21]
>
>
> в [18] жирным выделено важное замечание касаемое ИМЕННО
> stream-oriented sockets.. и речь здесь идет конкретно о
> stream-oriented sockets, а не о каких-то иных


Во-первых, ткни меня носом в тот пост, в котором написано, что автор вопроса использует SOCK_STREAM, а не SOCK_DGRAM. Из его кода это не следует. Во-вторых, если в чьём-то посте я увидел что-то такое, что противоречит тому, что я знаю, я что, имею право на уточняющий вопрос только в том случае, если это что-то выделено жирным шрифтом?


> Rouse_ ©   (17.06.04 14:03) [23]


Ну тогда всё понятно. В той ссылке, которую ты привел, сверху написано: Microsoft Windows CE .NET 4.2


 
Digitman ©   (2004-06-17 15:32) [25]


> Григорьев Антон ©   (17.06.04 15:03) [24]



> Во-первых, ткни


пожалуйста ..

в [15] у автора речь идет о почтовом протоколе POP3, который базируется на поточно-ориентированном транспортном протоколе


 
Rouse_ ©   (2004-06-17 15:37) [26]

> Во-первых, ткни меня носом в тот пост, в котором написано,
> что автор вопроса использует SOCK_STREAM, а не SOCK_DGRAM.


Цитирую:
> А там кроме первого знака "+" есть еще ОК#13#10.
Вопрос:
А ты видел чтоб такие сервера работали по UDP?


 
Rouse_ ©   (2004-06-17 15:37) [27]

О блин, долго пишу :)


 
Ivan K   (2004-06-17 16:31) [28]


> recv-то c 1024 будет ждать, пока данные в сокете
> появятся, хоть сколько данных, хоть один байт.
>
> if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR
> then
>
> Теперь bytes_in_buffer содержит кол-во байтов, которе на
> данный момент принял сокет со времени последнего recv. Эта-то
> ф-ция ничего не ждет. Она немедленно возвращает запрошенную
> информацию о состоянии буфера приема.


вот... спасибо. теперь понял, в чем тут фишка%)
простите за тормознутость%)


> if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR
>  then
> begin
>  if bytess_in_buffer > 0 then
>    C := Recv(Cs, A, bytes_in_buffer, 0); // Тут понятно
>  else
>     // А тут что ты намерен делать? Что дальше-то?
> end;


вооот... а вот тут вопрос интересный... теперь, в свете вновь полученных знаний, пока не знаю... По идее, если заголовок пока не прочитался, его надо прочитать, т.е. ждать, пока в Recv что-нить появится...


 
Rouse_ ©   (2004-06-17 16:46) [29]

Да хоть так делай:
repeat
 if ioctlsocket(Cs, FIONREAD, bytes_in_buffer) <> SOCKET_ERROR then
   if bytess_in_buffer > 0 then
     C := Recv(Cs, A, bytes_in_buffer, 0); // Тут понятно
until bytess_in_buffer > 0;


 
Григорьев Антон ©   (2004-06-17 16:50) [30]


> Rouse_ ©   (17.06.04 15:37) [26]
> > Во-первых, ткни меня носом в тот пост, в котором написано,
>
> > что автор вопроса использует SOCK_STREAM, а не SOCK_DGRAM.
>
> Цитирую:
> > А там кроме первого знака "+" есть еще ОК#13#10.
> Вопрос:
> А ты видел чтоб такие сервера работали по UDP?


Есть у меня пробел в образовании - я не знаком с протоколом POP3. Поэтому и не смог распознать, что это за сервер, пока не ткнули :))

Ладно, всем всё понятно, предлагаю прекратить этот оффтопик.


 
Verg ©   (2004-06-17 20:25) [31]


> [29] Rouse_ ©   (17.06.04 16:46)


А тогда зачем все это?

Просто Recv и все тут. Она сама подождет с таким же успехом.


 
Ivan K   (2004-06-17 22:50) [32]

2 Verg...

А если нечего ждать?%)
Попробую объяснить еще раз.
Цель - получить заголовки писем.
Реализация -
В цикле по i
Send(Sc, "Top " + i + " 0", Length("Top " + i + " 0"), 0)
Recv(Sc, A, bytes_in_buffer,0)
далее вычленение из А мыла, сабжа и пр.


Проблема была в том, что я не знал количество возвращаемых данных, а потому ставил наобум 1024 (мол, в килобайт-то поместится), пока не получил письмецо с заголовком поболе... В результате на обработке след. i ничего не нашлось (ибо не было в том аппендиксе никакой нужной инфы). Тогда мне в голову пришла идея! %))  - Надо вызывать Recv, пока он не вернет ошибку... тогда, мол, буфер пустой будет... Кто ж его, заразу, знал, что он дожидаться будет, пока данные откуда-нить возмутся... В результате имеем повешенную наглухо программу.
Вот с таким багажом я открыл сей топик... +)


 
Rouse_ ©   (2004-06-17 23:06) [33]

> [31] Verg ©   (17.06.04 20:25)
Я как понял условие непременно дождаться ответа, поэтому такой код :)


 
Ivan K   (2004-06-17 23:19) [34]

2 Rouse_ ©   (17.06.04 23:06) [33]
ну да, т.к. если в ответ на top 1 0 придет +ОК, то должен прийти и заголовок. (если что-то со связью не случится, но этот вопрос пока не поднимаю)


 
Digitman ©   (2004-06-18 08:25) [35]

Сигнал отклика в POP3 содержит индикатор состояния и ключевое слово, за которым может следовать дополнительная информация. Отклик также завершается кодовой последовательностью CRLF. Длина отклика не превышает 512 символов, включая CRLF.

Отклики на некоторые команды могут содержать несколько строк. В этом случае последняя строка содержит код завершения 046 ("."), за которым следует CRLF.


отсюда следует, что вызывать recv() и накапливать принятые байты отклика следует до тех пор, пока не будет принята строка "."#10#13


 
Digitman ©   (2004-06-18 08:26) [36]

замечание :

На практике многострочные отклики для исключения имитации завершаются последовательностью CRLF.CRLF.

т.е. признак конца отклика - прием строки "."#10#13#10#13


 
Ivan K   (2004-06-20 15:17) [37]


Digitman

>  Длина отклика не превышает 512 символов, включая CRLF.
>


Отклик-то может и менее 512 чимволов, а заголовок письма и более килобайта... Пример надо?



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

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

Наверх





Память: 0.58 MB
Время: 0.032 c
1-1092055407
oleg_
2004-08-09 16:43
2004.08.22
Как можно определить тип указателя на метод класса


14-1091102799
ИМХО
2004-07-29 16:06
2004.08.22
500-я ошибка


4-1089295110
Eugenez
2004-07-08 17:58
2004.08.22
Юзер на месте?


14-1091466244
Fay
2004-08-02 21:04
2004.08.22
Mozilla FireFox 0.9


3-1091096694
avs
2004-07-29 14:24
2004.08.22
Fastreport - программно изменить ориентацию страницы.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский