Форум: "Сети";
Текущий архив: 2006.09.10;
Скачать: [xml.tar.bz2];
ВнизWinSock Api Функция "Recv" : Что делать если буфер пуст ? Найти похожие ветки
← →
SPACE!! (2006-04-16 18:29) [0]Функция Recv вызывается в потоке TServerChatThread и потом
вызывается процедура ReciveChatData .
Вот она
procedure TServerChatThread.ReciveChatData;
var
ipos,g,i : integer;
argument1,argument2,argument3,argument4,commnd : string;
ClientData : String;
begin
g :=1;
i :=sizeof(g);
getsockopt(CLChat_socket,SOL_SOCKET,SO_ERROR,@g,i);
if (g = 0) and (In_buf[0] <> #0) then
begin
ClientData :=In_buf;
ipos := pos(#32,ClientData);\\До пробела идет команда.
commnd := copy(ClientData,1,ipos-1);
Delete(ClientData,1,ipos);
try
if strtoint(commnd) = CL_CHAT_MESSAGE then
begin
if Assigned(ChatForm) then ChatForm.Memo1.Lines.Append(Oponnents.Nik_2+" : "+ClientData);
Form1.Memo1.Lines.Append(In_buf);
end;
if strtoint(commnd) = CL_CHAT_TRYCONNECT then
begin
ShowDialogForm(clientdata,svChat);
end;
Except
Form1.Memo1.Lines.Append(In_buf);
end;
end
else
begin
bconnect :=False;
OnLostConnect;
if g = 0 then
begin
closesocket(CLChat_socket);
end;
end;
FillChar(In_buf,sizeof(In_buf),#0);
end;
Локально все работает прекрасно, а вот на просторах инета
In_buf оказывается в некоторых моментах пуст. Теоретически
помойму такого недолжно быть так-как сокеты работают в синхронном режиме.Я попытался несколько изменить код примерно иак ;
if (g = 0) then
begin
while In_buf[0] = #0 do
begin
;
end;
ClientData :=In_buf;
....
....
Также пробовал такой вариант :
if (g = 0) then
begin
if In_buf[0] = #0 then Exit;
ClientData :=In_buf;
....
....
Тоже ничего хорошего.. Help :)
← →
Сергей М. © (2006-04-17 08:32) [1]Показывай, как Recv() используешь ..
← →
SPACE!! (2006-04-17 17:55) [2]Recv вызывается в потоке TServerChatThread , в процедуре Execute :
while ((not Terminated) and (bconnect=true)) do
begin
recv(ChatClientSocket,Chat_In_buf,sizeof(Chat_In_buf),0);
Synchronize(ReciveServerData);
end;
← →
SPACE!! (2006-04-17 20:17) [3]Тоесть Synchronize(ReciveChatData).
Я непонимаю как Recv может вернуть управления при этом не заполнить
буфер и фиг что после этого сделаеш. Впринципе я фижу пару вариантов,
но это извращение.
1 . В процедуре ReciveChatData сделать так
var
z : integer
.....
z :=0;
while z <> 5000 do
begin
if In_buf[0] <> #0 then break;
inc(z);
end;
Но вопервых буфер не всегда успевает заполниться во вторых тормозит.
2. В конец данных ставить определенный символ и сканировать буффер
пока не найдется этот символ, но это тоже гнилой вариант.
← →
Rouse_ © (2006-04-17 21:48) [4]Т.е. ты просто в цикле ждешь ответа от синхронного recv? Мощно задвинуто...
recv вообщето функция которая возвращает результат...
Ты его не анализируешь.
← →
SPACE!! (2006-04-17 22:39) [5]Что-ты хочешь сказать что Recv вернет 0 в случаях когда буффер пуст ?
Ну допустим и что я после этого должен опять вызывать Recv ? :))
Насколько я понимаю событие возникшее при получение данных сбросится как только вызов Recv вернет управление ...
← →
SPACE!! (2006-04-18 00:12) [6]Блин ну что неужто все забыли что такое Winsock и перешли на компоненты ?
← →
SPACE!! (2006-04-18 01:01) [7]Вот нашел нормальное описание функции Recv .
Функция Recv копирует пришедшие данные из входного буфера сокета в буфер, заданный параметром Buf, но не более BufLen байт. Скопированные данные удаляются из буфера сокета. При этом все полученные данные сливаются в один поток, поэтому получатель может самостоятельно выбирать, какой объём данных считывать за один раз. Если за один раз была скопирована только часть пришедшего пакета, оставшаяся часть не пропадает, а будет скопирована при следующем вызове Recv. Функция Recv возвращает количество байт, скопированных в буфер. Если на момент её вызова входной буфер сокета пуст, она ждёт, когда там что-то появится, затем копирует полученные данные и лишь после этого возвращает управление вызвавшей её программе. Если Recv возвращает 0, это значит, что удалённый сокет корректно завершил соединение. Если соединение завершено некорректно (например, из-за обрыва кабеля или сбоя удалённого компьютера), функция завершается с ошибкой (т.е. возвращает Socket_Error).
Нифига не понимаю.
> Функция Recv возвращает количество байт, скопированных в
> буфер
Вопщето она возвращает размер переданого ей буфера ...
Что касается ошибок то их обрабатывает getsockopt заметьте.
var
z : integer
.....
z :=0;
while z <> 3000 do
begin
if In_buf[0] <> #0 then break;
inc(z);
end;
A вот при таком варианте наблюдалось следущая картина.
Я клиент (Diul-Up) шлю 7 сообсчений тестеру(ADSL) все доходят.
Он шлет сообсчения некоторые как в землю проваливаются видно
таймаут в 3000 маловат был . :))
И я уверен на 99% что у сервера при получении данных не возникает
фигни когда буфер оказывается пустым. Да и вопще судя из вышеописаного
описания Recv возвращает управления в случаи ошибок или получения данных исключения конешно асинхронный режим. Либо где-то ошибка либо я незнаю. Но данные застревают где-то. И клиент и сервер выполняются в отдельных потоках.
← →
Сергей М. © (2006-04-18 08:33) [8]
> Нифига не понимаю
Что не понимаешь ?
В этом тексте логика работы Recv() достаточно подробно описана ..
> Что касается ошибок то их обрабатывает getsockopt заметьте
1. если результат N > 0, в указанный буфер будет записано N байт;
2. если результат N = 0, следует закрывать гнездо - соединение закрыто по инициативе партнера;
3. если результат N < 0, произошла сетевая ошибка, код которой можно и нужно получить следом же вызовом WSAGetLastError()
Т.е. вызывать ReciveServerData() следует лишь в том случае, если N > 0, во всех остальных случаях вызов ReciveServerData() попросту не имеет смысла, ибо нет данных для обработки.
Да и смысл синхронизации тобой вызова ReciveServerData() тоже не понятен ...
Получается что у тебя организован одновременный прием данных от разных клиентов, а обработка принимаемых данных происходит последовательно...
← →
Сергей М. © (2006-04-18 08:34) [9]
> где-то ошибка либо я незнаю
На то есть встроенный отладчик.
← →
SPACE!! (2006-04-18 20:24) [10]
> 1. если результат N > 0, в указанный буфер будет записано
> N байт;
>
> 2. если результат N = 0, следует закрывать гнездо - соединение
> закрыто по инициативе партнера;
>
> 3. если результат N < 0, произошла сетевая ошибка, код которой
> можно и нужно получить следом же вызовом WSAGetLastError()
i :=sizeof(g);
getsockopt(CLChat_socket,SOL_SOCKET,SO_ERROR,@g,i);
if (g = 0) and (In_buf[0] <> #0) then
begin
Если нет ошибок то выполняем если они имеются значит закрываем
соеденения. Если их нет но буфер пуст значит Recv вернул 0 .
Чем тебя не устраивает такая проверка ? Я конешно поставлб проверку
на Recv , но знаешь я практически уверен что это не поможет.
end;
> Да и смысл синхронизации тобой вызова ReciveServerData()
> тоже не понятен
Она оаньше была другой да и чем она тебе мешает ?
> На то есть встроенный отладчик.
Ну это ты вопще зря.
> 1. если результат N > 0, в указанный буфер будет записано
> N байт;
Еще раз повторю фунция Recv возвращает размер переданого ей буфера
тоесть если мы передаем буфер размером 1024 байта, а пришло всего 10 байт, то N будет равен 1024 , но не 10 ... (Ненадо морочить людям головы)
← →
Rouse_ © (2006-04-18 21:57) [11]
> Еще раз повторю фунция Recv возвращает размер переданого
> ей буфера
Это у тебя странный Recv. MSDN же имеет по этому поводу другое мнение, а именно:
> If no error occurs, recv returns the number of bytes received
← →
SPACE!! (2006-04-18 23:49) [12]
> Это у тебя странный Recv. MSDN же имеет по этому поводу
> другое мнение, а именно
Да да признаю ошибочка , яж забыл что Send шлет и #0-ли. А зря. Ясно
надо будет сделать динамический буфер.. Но все-равно это не решает
проблемы. Думаю послезавтра вечером проверю свои идеи и сообщу
о результатах.
← →
Сергей М. © (2006-04-19 09:19) [13]
> SPACE!! (18.04.06 20:24) [10]
> Чем тебя не устраивает такая проверка ?
Да зачем так извращаться-то ?
Ты тем самым замесил в одну кучу транспортный и прикладной уровни, а теперь разобраться не можешь, что, где и почему у тебя происходит ...
Проверка на ошибку ввода-вывода должна происходить на транспортном уровне, а ты ее почему-то вынес в прикладной. ReciveChatData() - это у тебя как раз и есть прикладной уровень, т.е. уровень, предназначенный для обработки фактически принятых данных. Прикладному уровню не должно быть никакого дела до транспортного, его задача - обработать то что ему передано на обработку, поэтому процедуру ReciveChatData() следовало бы даже назвать иначе ...
Проиллюстрирую эту мысль в псевдокоде, чтобы тебе стало понятно :
var Buf: array[0..4096] of Byte; //буфер можно распределить и иначе, это не суть как важно
..
//транспортый уровень
//цикл, принимающий поток данных от партнера по соединению
while Connected do
try
BytesReceived := Recv(hSocket, Buf, SizeOf(Buf));
CheckWSAResult(BytesReceived); //здесь генерируется исключение, если BytesReceived < 0
Connected := BytesReceived > 0;
//если имеются фактияески принятые данные, то передаем их на обработку прикл.уровню, укказав их местонахождение и размер
if Connected then ProcessIncomingData(Buf, BytesReceived);
except
Connected := False;
end;
..
//прикл.уровень
procedure ProcessIncomingData(var Data; Size: Integer);
begin
.. разбор принятого ..
end;
← →
SPACE!! (2006-04-19 20:21) [14]Сергей М спасибо конешно за жедания помочь , но вопервых все ошибки
связанные с передачей данных решаются как раз таки транспортным протоколом... тоесть данные просто не дайдут до уровня приложения
если где-то к примеру в заголовке небудет совподать чексумма я прав или
я прав :) ? А вот при не нормальном закрытие соеденения при передаче
или при получение данных возникнет ошибка это-то и проверяет getsockopt.
Во вторых локально все работает прекрасно. В третих яж сказал что
добавлю такую проверку. Ну а вопще я вроде нашел ошибку проверю только завтра : Дело в том что функция Send шлет буфер размером MAXPACKETSIZE(65535) предварительно он заполняется нулями
FillChar(buf,sizeof(buf),#0);
Ну я незнаю просто меня переклинило что он шлет только полезную информацию и все тут :))) . Вот данные и застревают.... Впервые
наверно допускаю такую смешную ошибку на которую уходит столько времени . Ладненька народ завтра проверю сообщу результаты .
← →
Сергей М. © (2006-04-21 08:53) [15]
> вопервых все ошибки
> связанные с передачей данных решаются как раз таки транспортным
> протоколом
Не путай транспортный протокол в соответствии с OSI (в дан.случае - TCP) с транспортным уровнем в прикладной задаче (в дан.случае - набор каких-то твоих ф-ций/процедур, занимающихся исключительно установкой соединения, приемом-передачей неких данных по этому соединению и обработкой ошибок приема-передачи).
> если где-то к примеру в заголовке небудет совподать чексумма
> я прав или
"чексуммы" тебя никак не касаются в дан.случае.
Этим занимается TCP/IP.
> добавлю такую проверку
Тогда getsockopt() становится нужным как 5-е колесо телеге.
← →
SPACE!! (2006-04-22 23:55) [16]Ох ну и нудный ты Сергей =)
> > вопервых все ошибки
> > связанные с передачей данных решаются как раз таки транспортным
> > протоколом
>
>
> Не путай транспортный протокол в соответствии с OSI (в дан.
> случае - TCP) с транспортным уровнем в прикладной задаче
> (в дан.случае - набор каких-то твоих ф-ций/процедур, занимающихся
> исключительно установкой соединения, приемом-передачей
> неких данных по этому соединению и обработкой ошибок приема-
> передачи).
А никто и не путает это ты чего-то путаешь. Eсть ошибка вызов getsockopt
в твоем транспортно-прикладном уровне все обнаружит главное правильно
пользоваться этой функцией и проверять не заполнен ли буфер с прошлого вызова. Поверь мне getsockopt прекрасно справляется со своими обязаностями и в моем случаи проверка Recv была бы уже лишней ... :)
И конешно было бы лишней вызывать getsockopt еслиб я проверял Recv .
> "чексуммы" тебя никак не касаются в дан.случае.
> Этим занимается TCP/IP
Вот именно я тебе это и хотел сказать, тоесть нас интересует только в порядке ли "socket" я думаю первым делом этим и занимаются вызовы
Recv и Send не удивлюсь даже если они используют для этого функцию getsockopt :))) .
Только давай небудем спорить как лучше проверять ... :) Так-как я уже
сказал что добавлю проверку на Recv.
Все заработало, я исправил ошибку описанную в предыдущем посте.
Динамические масивы использовать не получилась странно даже , дело
в том что символы переданные с помощью динамического массива преобразуются в абра-кадабру. Как я понял для функции Send динамический
массив не подходит или как ?
← →
Сергей М. © (2006-04-24 08:49) [17]var
MyDynArray: array of Byte;
..
SendResult := Send(@MyDynArray[0], Length(MyDynArray));
..
RecvResult := Recv(@MyDynArray[0], Length(MyDynArray));
← →
SPACE!! (2006-04-24 23:54) [18]Спасибо , я честно говоря хотел так попробовать , но чето не рискнул =)
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2006.09.10;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.037 c