Передача файла
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.217.172] |
|
|
Соблюдайте общие правила форума
MSDN Library
FAQ раздела
Поиск по разделу
Как правильно задавать вопросы| Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Передача файла
|
Сообщ.
#1
,
|
|
|
|
Процедура отправки файла
![]() ![]() procedure TForm1.UserQuery(Socket: TCustomWinSocket; Msg: PUserQueryMsg; Size: Integer); var M: TServerSendFileMsg; begin M.MsgNumber := MSG_SERVERSENDFILE; M.FileName := Msg.FileName; M.FileData := TMemoryStream.Create; M.FileData.LoadFromFile(Dir + '\' + M.FileName); M.FileData.Position := 0; Socket.SendBuf(M,SizeOf(TServerSendFileMsg)); Sleep(30); Socket.SendStream(M.FileData); end; Процедура приема файла ![]() ![]() procedure TForm1.ServerSendFile(Msg: PServerSendFileMsg; Socket: TCustomWinSocket); var len: integer; ToFile: TMemoryStream; buff: array[0..524288] of byte; begin len := Socket.ReceiveLength; ToFile := TMemoryStream.Create; Socket.ReceiveBuf(buff,len); ToFile.Write(buff,len); ToFile.Position := 0; ToFile.SaveToFile(SaveDialog1.FileName); end; Файл сохраняется пустой. Что не так? |
|
Сообщ.
#2
,
|
|
|
|
1. M.FileName - string? тогда бессмысленно отправлять его в сокет, это опять же только указатель.
2. Зачем Sleep? 3. Если сделали Send 2 раза, то и Receive логично 2 раза делать. Первый - прочитали заголовок, если наш, читаем контент. |
|
Сообщ.
#3
,
|
|
|
|
Перед вызовом процедуры ServerSendFile вызываются вот эти процедуры
![]() ![]() procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); var Msg: Pointer; Size: integer; begin Size := Socket.ReceiveLength; if Size > 0 then begin GetMem(Msg,Size); Socket.ReceiveBuf(Msg^,Size); HandleMessage(Msg,Socket); FreeMem(Msg); end; end; procedure TForm1.HandleMessage(Msg: Pointer; Socket: TCustomWinSocket); begin case integer(Msg^) of MSG_SERVERSENDFILELIST: ServerSendFileList(Msg,Socket); MSG_SERVERSENDFILE: ServerSendFile(Msg,Socket); end; end; |
|
Сообщ.
#4
,
|
|
|
|
hawk1
Какой протокол используете TCP или UDP? Добавлено Цитата Relaxander @ 3. Если сделали Send 2 раза, то и Receive логично 2 раза делать. Первый - прочитали заголовок, если наш, читаем контент. С чего бы в друг. ;-) |
|
Сообщ.
#5
,
|
|
|
|
TCP
|
|
Сообщ.
#6
,
|
|
|
|
Всё что пришло ты уже вычитал в
Size := Socket.ReceiveLength; Socket.ReceiveBuf(Msg^,Size); следующий вызов Socket.ReceiveBuf просто читает 0. ReceiveBuf работает в не блокирующем режиме, а другая порция по росту не успела прийти на момент вызова процедуры. Короче говоря учите матчасть. Код совершенно неправильный, его надо переделывать. 1. Стивенс. UNIX. Разработка сетевых приложений. 2. Э. Джонс, Д. Оланд -Программирование_в_сетях_Microsoft_Windows-Питер(2002) Желательно читать именно в таком порядке. |
|
Сообщ.
#7
,
|
|
|
|
Переделал так
Передача ![]() ![]() procedure TForm1.UserQuery(Socket: TCustomWinSocket; Msg: PUserQueryMsg; Size: Integer); var M: TServerSendFileMsg; FileData: TMemoryStream; buf: array[0..524288] of byte; begin M.MsgNumber := MSG_SERVERSENDFILE; M.FileName := Msg.FileName; FileData := TMemoryStream.Create; FileData.LoadFromFile(Dir + '\' + M.FileName); FileData.Position := 0; FileData.WriteBuffer(buf,FileData.Size); M.Size := FileData.Size; Socket.SendBuf(M,SizeOf(TServerSendFileMsg)); Sleep(30); Socket.SendBuf(buf,FileData.Size); end; Прием ![]() ![]() procedure TForm1.ServerSendFile(Msg: PServerSendFileMsg; Socket: TCustomWinSocket); var ToFile: TMemoryStream; len: integer; buf: array [0..524288] of byte; begin len := Socket.ReceiveLength; Socket.ReceiveBuf(buf,len); ToFile := TMemoryStream.Create; ToFile.ReadBuffer(buf,len); ToFile.Position := 0; ToFile.SaveToFile(SaveDialog1.FileName); end; На принимающем конце все равно пусто |
|
Сообщ.
#8
,
|
|
|
|
hawk1
Всё равно всё неправильно. Ещё раз учите матчасть. Есть разные режимы передачи данных. Так вот вы сейчас работаете в неблокирующем режиме с ожиданием подтверждения по каждому пакту. Неблокирующий режим означает что ReadBuffer не ждет пришли данные или не пришли, а возвращает что есть. Следовательно на приемной стороне нужна синхронизация. Ставим барьер ждем пока придут нужные данные читаем. И писать надо тоже по другому. Размер пакет гораздо меньше файла поэтому надо разбивать на пакеты. С подтверждением означает что на каждый ушедший пакет приходит пакет с подтверждением. А следовательно передача тоже идет пакетами. Так как в TCP отправка идет с подтверждением. То, в обработчике сетевых событий, вы можете вызывать только один раз чтение и только одну запись. Для файлов лучше передавать не пакетом, а потоком SendStream. Передача потоком это режим когда посылка следующих пакетов идет без подтверждения о приеме предыдущих пакетов. А проверка того что всё отправилось происходит уже по окончанию. Помимо скорости передачи от передачи потоком есть плюс не надо ручками разбивать передачу на пакеты. Правда при плохой связи ручками разбивать на пакеты придется иначе всё будет зависать. |
|
Сообщ.
#9
,
|
|
|
|
Цитата hawk1 @ Переделал так а что ожидается в ToFile? содержимое файла или все сообщение, включая заголовок? |
|
Сообщ.
#10
,
|
|
|
|
Цитата Relaxander @ Содержимое файла |
|
Сообщ.
#11
,
|
|
|
|
почему бы не сделать так
![]() ![]() // передача var FileContent: PByte; FileContent := AllocMem(FileSize); Stream.LoadFromFile(FileName); Stream.Read(FileContent^, FileSize); MsgNumber := MSG_SERVERSENDFILE; Socket.SendBuf(MsgNumber,SizeOf(MsgNumber)); Socket.SendBuf(FileContent^,FileSize); FreeMem(FileContent); // прием в MemoryStream Socket.ReceiveBuf(MsgNumber,SizeOf(MsgNumber)); if (MsgNuber = MSG_SERVERSENDFILE) then while Socket.ReceiveBuf(Buff,BuffSize) > 0 do begin Stream.Write(Buff,BuffSize); end; Stream.SaveToFile(FileName); end; |
|
Сообщ.
#12
,
|
|
|
|
Relaxander
А справка для кого написана? Ошибки все тежи. Разве что ещё добавилась одна ошибка в Stream.Write(Buff,BuffSize); - у вас мусор будет писаться в файл. Так как вы не праверяете сколько байт пришло. А также ошибка с отправкой тоже не проверяете сколько ушло. |
|
Сообщ.
#13
,
|
|
|
|
Цитата Pavia @ Ошибки все тежи например? Цитата Pavia @ не праверяете сколько байт пришло я общую идею набросал понятно, что всяческих проверок не хватает repeat BytesRead := Socket.ReceiveBuf(Buff,BuffSize); if (BytesRead > 0) then Stream.Write(Buff,BytesRead); until BytesRead <= 0; |
|
Сообщ.
#14
,
|
|
|
|
Relaxander
Использовать цикл нельзя. Так как не будет сообщение о доставки и следовательно и отправка другой порции данных. За раз в сообщение можно читать только один раз. А повторная запись скорее всего тоже блокируется и возвращает 0. Я бы так сделал для предотвращения переполнения внутренних буферов. |
|
Сообщ.
#15
,
|
|
|
|
Нужно делать автомат состояний.
В состояние 0 ждем прием команды на передачу файла в состояние 1 читаем порцию данные, можно сразу писать в файл в состояние 2 информируем о завершение чтения закрываем файл переход из 0 по пришедшей команде переход из 1 во второму по счётчику принятых байт переход из 2 в 0 после отработки логики. И плюс, проверки на ошибки. Повторная посылка в случае потери пакета. Проверка обрыва связи и повторное восстановление. Точно также с записью. Причем для устойчивости скорее всего придется добавлять терминальные символы в поток. А это значит что надо будет экранировать их в исходном файле. Либо разделять передачу и команды на разные сеансы, порты. Последнее хоть и популярно но снижает производительность. |