![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вопрос про сокеты, а точнее про FD_CLOSE и FD_READ [D6, Win95/98, WinME, Win2k, WinXP]
__Unnamed__ © (2007-10-01 17:52:00)Сделал сервак на основе сокетов. Использовал WS Api функции. Обработка информации происходит следуюющим образом:
Да это все в потоке :)
While not Terminated do
Begin
Res:=WaitForMultiPleObjects(1,FSockEvent,False,100,Flase);
Case Res Of
0: Begin
...
<здесь проверяю флаги>
FD_CLOSE
FD_READ
FD_WRITE
...
End;
End;
End;
Суть вопроса! :)
Выявил следующую ошибку.
Когда передаю большой файл >1Mb по нескольким соединениям(т.е. различные файлы, но соединений более 1-го) иногда не доходит до получателя последний блок. Экспериментальным путем выявил, что FD_Close приходит раньше, чем FD_READ.
Т.к. сервер не мой (т.е. не мною писанный). логика сервера заключается в том, что при посылке конечного куска файла он завершает соединение Shutdown + CloseSocket Или просто CloseSocket (Онное мне не известно).
Как я помню из сокетов на основе оконных функций FD_CLOSE приходит всегда после того как прийдет последний байт из буфера чтения.
Еще прочитал про критические секции, возможно в этом решение. Т.к. при изучении модуля ScktComp обнаружил, что любая операция I/O заключена в Enter и Leave.
Скажите не потеряется ли быстродействие и независимость самого потока при использовании критических секций.
Или же моя ошибка заключается в другом? :)
Palladin (2009-03-12 08:28:00) [1]
> FireMan_Alexey (04.02.09 18:29) [43]
А ничего что год прошел? :)
!"№;%:?* (2009-03-12 07:30:00) [2]При известном количестве данных - читай сколько указано в заголовке, recv вернет ошибку если соединение будет закныто раньше.
В отдельном потоке, можно и блокирующими сокетами обойтись.
FireMan_Alexey (2009-02-04 18:29:00) [3]Сделай так:
While True do
Begin
Err:=Recv(...);
IF err=SOCKET_ERROR and WSAGetLastError=WSAEWOULDBLOCK Then
Break;
End;
Event - сигнализирует о приходе данных, а IOCTLSocket - покажет всего 8192 макс хотя там может быть и больше :) (проверенно экспериментально)
А вообще лучше использовать Select в потоках :) тоже экспериментально :)
Я тоже пытался прокси на Эвентах написать, но столкнулся с такой же ситуацией и с не закрытыми соединениями со стороны апачей :).
Спасло только то что весь код переделал под синхронные сокеты.
(2009-02-04 17:32:00) [4]Удалено модератором
ага (2008-02-06 13:22:00) [5]Просмотрел бегло, может уже сказано, но не заметил.
Нормально это, FIN пришел вместе с последним пакетом. Сервер закончил запись и вызвал shutdown на свой передающий конец - типа больше ниче передавать не буду. Сокет отправил все из буфера и с последним пакетом - FIN. Получив его, нужно вычерпать все из буфера и закрыть свой приемный конец.
(2008-02-05 19:35:00) [6]Удалено модератором
Сергей М. (2007-10-05 08:58:00) [7]Даже если поступил FIN, данные в буфере приема твоего гнезда, если они там действительно имеются, никуда не денутся, и ты сможешь их прочитать в любой момент до закрытия своего гнезда.
> мне прийдется анализировать
> <Content-length:?????>
Да, придется.
__Unnamed__ (2007-10-04 20:28:00) [8]Скажи, а если у меня происходит скажем задержка потока на 1-5 секунды в связи с записью на устройство. И чтение из буфера приемника задерживается, то по логике TCP FIN прийдет только тогда, когда Апач полностью передаст данные, ну или у него SO_LINGER=False и прийдет дисконнект но в буфере приемника может быть где-то до 8-64Кб информации как я понимаю.
И мне кажеться в моем случае, мне прийдется анализировать
<Content-length:?????> + FD_CLOSE и его ошибки. Если при дисконнекте произошли ошибки, то выходить иначе читать до тех пор пока не будет равно ожидаемого.
Сергей М. (2007-10-04 13:16:00) [9]Подозреваю, что где-то что-то ты недопонимаешь.
Вряд ли Апач будет рвать соединение не передав полностью запрошенные у него данные, если на то нет веских причин.
Пробуй ту же логику в блокирующем режиме. Если все будет ок, то неправ ты, иначе Апач.
Сергей М. (2007-10-04 13:12:00) [10]Это, в свою очередь, зависит от Interval.
__Unnamed__ (2007-10-04 13:01:00) [11]Т.е. при SO_LINGER = TRUE с моей стороны, все данные будут приняты?
Или это только для посылки?
Сергей М. (2007-10-04 12:51:00) [12]Весьма полезным будет также изучить поведение гнезда при его закрытии при взведенной и сброшенной опции SO_LINGER
__Unnamed__ (2007-10-04 12:49:00) [13]>>Сергей М. ©
Ну так первым дело м при этом ты должен был искать в списке событий, возвращенных вызовом этой ф-ции, событие FD_READ и только потом FD_CLOSE, но не наоборот.
См. топик [9]!!!
Сергей М. (2007-10-04 12:48:00) [14]
> когда я не выполняю ShutDown сам Апаче сервер не закрывает
> со своей стороны Гнезда и ждет непонятно чего
Быть того не может.
Если ты выполнил без ошибок closesocket, то рано или поздно партнер получит FIN.
__Unnamed__ (2007-10-04 12:47:00) [15]Я столкнулся с такой проблемой, когда я не выполняю ShutDown сам Апаче сервер не закрывает со своей стороны Гнезда и ждет непонятно чего??!!!!!
А с ShutDown все нормально :)
Сергей М. (2007-10-04 12:46:00) [16]
> я так и делал
Ну так первым дело м при этом ты должен был искать в списке событий, возвращенных вызовом этой ф-ции, событие FD_READ и только потом FD_CLOSE, но не наоборот.
Сергей М. (2007-10-04 12:44:00) [17]
> Как можно проверить с каким пар-ром ShutDown был выполнен
> с серверной стороны?
Кроме анализа текста сервера - никак.
Кстати, Апач - опенсурсный продукт.
> Я со своей стороны выполняю всегда ShutDown(FServerS, ??
> _BOTH);
Нафига ?
__Unnamed__ (2007-10-04 12:42:00) [18]Ну и CloseSocket после ShutDown соотвественно :)
__Unnamed__ (2007-10-04 12:42:00) [19]1. Сервер Apache но локально(хотя это не имеет значения)
2. Рекомендации Slym-а смотрел см [9], я так и делал просто когда писал вопрос, первое что в голову пришло это было FD_CLOSE :)
Как можно проверить с каким пар-ром ShutDown был выполнен с серверной стороны? Я про это еще нигде не видел примеров и статей :)
Я со своей стороны выполняю всегда ShutDown(FServerS, ??_BOTH);
Сергей М. (2007-10-04 12:42:00) [20]Короче, сервер вполне м.б. "кривым".
Ну а твоя "кривизна" как клиента исправляется задействованием WSAEnumNetWorkEvents