Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Переслать несколько больших файлов Client/Serv Socket [D5, WinXP]


Страницы:   1 2

kami ©   (2005-07-23 20:31:00) 

ClientSocket, получив запрос на пересылку нескольких больших файлов, честно пытается их передать:

var
 FileNames:TStringList;
 fs:TFileStream;
//==================
 for i:=0 to FileNames.Count-1 do
   begin
     //========
     ClientSocket.Socket.SendStream(fs);(упрощенно, но суть та же, если нужно, приведу более полный код)
    end;

Проблема в том, что на середине передачи первого файлового потока во внутренностях ClientSocket.SendStream "вылазит" ошибка WSAEWOULDBLOCK - вроде, действительно, нефатально,  но передача прерывается и происходит возврат в приведенный код => попытка отправить след.файл - и, естественно, безрезультатно, т.к. Socket.FSendStream занят :(

Пока помогает ProcessMessages, но предполагается работа в сервисе, так что отпадает(?).

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


kami   (2005-07-30 18:50:00) [1]

2 [37] Масяня ©
Лучше прочитай ветку полностью - UDP я использую только для обнаружения сервера в сети, потом вступают в действие Client/ServerSocket в ctNonBlocking. Более того - это уже пройденный этап, всё протестено неоднократно на файлах разного объема и количества. Теперь меня интересует [36]
PS. Прошу не принять за оскорбление.


Масяня   (2005-07-30 18:42:00) [2]


> tesseract ©   (23.07.05 20:58) [1]
> Передавай файл небольшими блоками примерно по 1500 бит (Ethernet)
> Используй  UDP и проверяй их контрольную сумму - UDP быстрее
> но CRC не поддерживает

лучше через TCP - хоть медленней UDP, зато надежней


kami   (2005-07-30 17:44:00) [3]

Итак, проблема вроде решена (относительно, конечно - всегда найдется какое-нибудь узкое место).
Остался один вопрос, уже озвученный здесь - обработку чего еще (из "плохих" ситуаций) нужно предусмотреть.
На данный момент сделано следующее:

0. Преполнение буфера передачи (спасибо всем !)
1. Таймаут ожидания очередного пакета (спасибо Verg ©)
2. Потеря части инфы по пути (реализована грубо, просто идет пропуск до следующего заголовка)
3. Disconnect, SocketError (c последним пришлось довольно долго помучиться, особенно когда создавал ошибку при передаче нескольких файлов)
4. Разбиение и склейка пакетов .


Verg   (2005-07-26 22:10:00) [4]


> kami ©   (26.07.05 22:01) [34]


Оно все отсылает буферами - "сутба такой". Будешь ли ползоваться SendStream, который сам это делеает (внутри), то ли как Alexander Panov (снаружи), у котрого некий эквивалент - дело твое. Суть же та же.


kami   (2005-07-26 22:01:00) [5]

Да, если пользоваться SendStream, но у меня по примеру [11] Alexander Panov © отсылается буферами, а Delete(0) не делает Objects[0]=nil и, ко всему прочему, если это файловый поток, не освобождает сам файл.


Verg   (2005-07-26 18:51:00) [6]


> поэтому сперва делаю (Objects[0] as TStream).Free


Free сделает сам SendStream, так что, твое действие даже врдно, чем просто лишнее.


Verg   (2005-07-26 18:45:00) [7]

FD_WRITE возникает в двух случаях:

1. Успешное установление TCP соединения. (собтвенно OnWrite  -это и есть признак успешно установленного соединения)
2. Сокет способен сновапринять данные после случаяотказа (WSAEWOULDBLOCK) это сделать.


kami   (2005-07-26 17:32:00) [8]

2 [30] Verg ©
Больше всего порадовала организация TMyFileStream, особенно методы Seek&Read - мне даже в голову не приходило так хранить заголовок и оперировать им:))

Единственное - TStringList.Delete(x) почему-то (у меня, по крайней мере) не закрывает файлы (обнаружил в ProcessExplorer), поэтому сперва делаю (Objects[0] as TStream).Free, а потом уже - Delete.

У меня по смыслу примерно такая же организация приема/передачи, за исключением потоков :), осталось только внести некоторые изменения в соотв. с Вашим примером, касающиеся Disconnect`ов и времени, отведенного на прием очередного пакета.

Блин!!!
Посмотрел, как и советовали WSAAsyncSelect  - ну и редиски эти Борланды!
в хелпе (из всей литературы пользуюсь только им)
OnWrite : should write information to the socket connection - должен(если переводить буквально, как я и делаю) записать инф-ю в сокет.

MSDN:
FD_WRITE: Socket s ready for writing - сокет(ы) готов к записи.

Согласитесь, разница между "должен" и "можно" - довольно большая, вот я и не представлял, как OnWrite можно использовать до сего времени :(.


Verg   (2005-07-26 14:43:00) [9]

Посмотри, может поможет

http://webfile.ru/424325


kami   (2005-07-26 09:17:00) [10]

Конечно, интересно !


Alexander Panov   (2005-07-26 01:28:00) [11]

kami ©   (25.07.05 23:17) [27]
Еще раз повторю - основная задача - кинуть на форму 2 компонента - и забыть о приеме/передаче, заниматься только обработкой данных.


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


kami   (2005-07-25 23:17:00) [12]

Так протокол обмена есть (там выложена ранняя-ранняя версия, с тех пор всё поменялось). Единственное, может обработка ошибок не совсем реализована, но даже в той версии глюков при передаче не было - не говоря уже об этой. (правда, тестировалось все в (не знаю, как правильно назвать) домашних сетях без сервера, с 1-2 хабами.
К стати, где можно почитать про это (в смысле, возможные ошибки при передаче и их обработку. Ну, обработку, это понятно, сам реализую - хоть и чайник, но понимаю быстро).
Еще раз повторю - основная задача - кинуть на форму 2 компонента - и забыть о приеме/передаче, заниматься только обработкой данных.


Alexander Panov   (2005-07-25 23:06:00) [13]

kami ©   (25.07.05 22:55) [25]
что данные в потоке еще есть, а ничего не считано?


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

В [11] только макет. Обязательно нужна обработка ошибок.

kami ©   (25.07.05 22:55) [25]
Ну а конечная задача - http://www.kladovka.net.ru/index.cgi?pid=list&rid=202;основной обмен - при пересылке измененных частей экрана и файлов. Детская игрушка, в которой захотелось поменять протокол обмена и саму систему взаимодействия, как уже описал, чтобы потом на любую программу для локалки можно было кинуть 2 или 1 компонента(в зависимости от задачи) - и практически все готово.


Тебе нужно реализовать протокол обмена, тогда вопросов об извещении кого-либо не возникнет.

Самые зачатки протокола в [11] есть, но все несколко сложнее.


kami   (2005-07-25 22:55:00) [14]

Сейчас, после глобального тестирования с пересылкой кучи файлов разных размеров, проблем вроде не наблюдаю. Интересно просто было узнать, как оценивают такой подход профи. Да и (главное!) узнать, как все-таки справиться с задачей перекрытием Stream.Destroy по предложению[19] Verg © - сам дойти до этого не могу.
Кроме того, я работаю в stNonBlocking
Ну а конечная задача - http://www.kladovka.net.ru/index.cgi?pid=list&rid=202;основной обмен - при пересылке измененных частей экрана и файлов. Детская игрушка, в которой захотелось поменять протокол обмена и саму систему взаимодействия, как уже описал, чтобы потом на любую программу для локалки можно было кинуть 2 или 1 компонента(в зависимости от задачи) - и практически все готово.

АААаааа..... чуть не забыл !!!
Может ли быть такая ситуация,
From [11] Alexander Panov ©
> Readed := FS.Read(Buf[0],8192);

что данные в потоке еще есть, а ничего не считано?


Alexander Panov   (2005-07-25 22:36:00) [15]

В интернете, к сожалению, лежат все примеры кривые(по крайней мере, я не нашел правильного) для реализации сервера в stThreadBlocking.

Если надо, выложу пример снервера и в этом режиме...

Если у тебя идет интенсивный обмен, то скорее всего в режиме stNonBlocking сервер не устроит тебя.

Почему я спросил, какова конечная задача? Потому что непонятно, в каком месте у тебя проблемы.


Alexander Panov   (2005-07-25 22:30:00) [16]

kami ©   (25.07.05 21:46) [22]
С самим приемом проблем нет никаких - склейка и разбиение по пакетам "разруливается на ура". Не могу придумать организацию передачи, чтобы Stream "предупреждал"(как и кого?),


А зачем тебе предупреждать? У тебя есть очередь на отправку. После завершения отправки предудущего файла ты сразу же стартуешь новую отправку.

Честно говоря, было бы лучше, если бы ты описал конечную задачу.


kami   (2005-07-25 21:46:00) [17]

Спасайте...После наряда голова не работает, а хочется...
Вообще запутался, не могу придумать, как это использовать. Нет, с перекрытием деструктора проблем никаких, но вот что с ним делать - не соображу :(

В общем, на данный момент ситуация такая:
На стороне сервера каждому CustomWinSocket сопоставлен мой экз.класса(runtime-created); вызываемый при OnClientRead и при необходимости передачи клиенту информации. Он "единолично" отвечает за прием/передачу, и "родителю" отдает полностью принятый Stream и его хедер.На стороне клиента - точно такой же, но, ессно, один.
При получении запроса на передачу какой-либо информации, в StringList заносятся Stream`ы, каждый со своим хедером и вызывается метод передачи инф-и моего компонента.
С самим приемом проблем нет никаких - склейка и разбиение по пакетам "разруливается на ура". Не могу придумать организацию передачи, чтобы Stream "предупреждал"(как и кого?), что его уничтожают, и, соответственно, можно начинать передачу следующего.

Пока сделал так(thnks to Alexander Panov © за идею и Verg © за поддержку): при вызове метода пересылки инф-и она просто заносится в StringList(Sorted:=False,Duplicates:=dupAccept), затем вызывается непосредственно процедура пересылки:
1. записываем в сокет части потока [0], пока не скажут "хватит"
2. если поток [0] закончился, удаляем его и продолжаем с нового [0]
3. выходим.

у CustomWinSocket переопределяем событие OnSocketEvent, в котором проверяем, если пришло seWrite, то goto 1.

Пока - работает, но - правильно ли сделано?

Если да, то остается только сказать:
"Да здравствует пиво - главная движущая сила IT индустрии !" (с) Набережных С.


Alexander Panov   (2005-07-25 19:15:00) [18]

Verg ©   (25.07.05 17:25) [19]
- Это не число коллизий


Это понятно. я имел ввиду количество возникающих ситуаций "занятости" сокета при передаче больших объемов информации.


kami   (2005-07-25 18:49:00) [19]

Строго говоря, передаются-то не одни файлы, а еще много другой информации в MemoryStream по запросу сервера(файлы, само собой FileStream), причем когда что передавать - решает сервер. Естественно, сохранить список только имен файлов было бы великолепно, но - неполучится.

А насчет перекрытия деструктора - здОрово, щаз буду думать и делать :)


Verg   (2005-07-25 17:25:00) [20]


> WSAEWOULDBLOCK


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


> пока вижу выход в том, чтобы сохранять потоки в чем-нибудь
> типа StringList, отсылать по одному(в смысле, по частям),
> как [11] Alexander Panov ©, и переданные удалять.


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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо