На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

Модераторы: Krid, Rouse_
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Передача файла
    Процедура отправки файла
    ExpandedWrap disabled
      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;

    Процедура приема файла
    ExpandedWrap disabled
      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;

    Файл сохраняется пустой. Что не так?
      1. M.FileName - string? тогда бессмысленно отправлять его в сокет, это опять же только указатель.
      2. Зачем Sleep?
      3. Если сделали Send 2 раза, то и Receive логично 2 раза делать. Первый - прочитали заголовок, если наш, читаем контент.
        Перед вызовом процедуры ServerSendFile вызываются вот эти процедуры
        ExpandedWrap disabled
          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;
          hawk1
          Какой протокол используете TCP или UDP?

          Добавлено
          Цитата Relaxander @
          3. Если сделали Send 2 раза, то и Receive логично 2 раза делать. Первый - прочитали заголовок, если наш, читаем контент.

          С чего бы в друг. ;-) :popcorn:
            TCP
              Всё что пришло ты уже вычитал в
              Size := Socket.ReceiveLength;
              Socket.ReceiveBuf(Msg^,Size);
              следующий вызов Socket.ReceiveBuf просто читает 0. ReceiveBuf работает в не блокирующем режиме, а другая порция по росту не успела прийти на момент вызова процедуры.

              Короче говоря учите матчасть. Код совершенно неправильный, его надо переделывать.

              1. Стивенс. UNIX. Разработка сетевых приложений.
              2. Э. Джонс, Д. Оланд -Программирование_в_сетях_Microsoft_Windows-Питер(2002)

              Желательно читать именно в таком порядке.
                Переделал так
                Передача
                ExpandedWrap disabled
                  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;

                Прием
                ExpandedWrap disabled
                  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;

                На принимающем конце все равно пусто
                  hawk1
                  Всё равно всё неправильно. Ещё раз учите матчасть.
                  Есть разные режимы передачи данных. Так вот вы сейчас работаете в неблокирующем режиме с ожиданием подтверждения по каждому пакту.
                  Неблокирующий режим означает что ReadBuffer не ждет пришли данные или не пришли, а возвращает что есть. Следовательно на приемной стороне нужна синхронизация. Ставим барьер ждем пока придут нужные данные читаем. И писать надо тоже по другому. Размер пакет гораздо меньше файла поэтому надо разбивать на пакеты.
                  С подтверждением означает что на каждый ушедший пакет приходит пакет с подтверждением. А следовательно передача тоже идет пакетами.

                  Так как в TCP отправка идет с подтверждением. То, в обработчике сетевых событий, вы можете вызывать только один раз чтение и только одну запись.

                  Для файлов лучше передавать не пакетом, а потоком SendStream. Передача потоком это режим когда посылка следующих пакетов идет без подтверждения о приеме предыдущих пакетов. А проверка того что всё отправилось происходит уже по окончанию. Помимо скорости передачи от передачи потоком есть плюс не надо ручками разбивать передачу на пакеты.
                  Правда при плохой связи ручками разбивать на пакеты придется иначе всё будет зависать.
                  Сообщение отредактировано: Pavia -
                    Цитата hawk1 @
                    Переделал так

                    а что ожидается в ToFile?
                    содержимое файла или все сообщение, включая заголовок?
                      Цитата Relaxander @

                      Содержимое файла
                        почему бы не сделать так
                        ExpandedWrap disabled
                          // передача
                          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;
                        Сообщение отредактировано: Relaxander -
                          Relaxander
                          А справка для кого написана?
                          Ошибки все тежи.
                          Разве что ещё добавилась одна ошибка в
                          Stream.Write(Buff,BuffSize); - у вас мусор будет писаться в файл. Так как вы не праверяете сколько байт пришло. А также ошибка с отправкой тоже не проверяете сколько ушло.
                            Цитата Pavia @
                            Ошибки все тежи

                            например?
                            Цитата Pavia @
                            не праверяете сколько байт пришло

                            я общую идею набросал
                            понятно, что всяческих проверок не хватает
                            repeat
                            BytesRead := Socket.ReceiveBuf(Buff,BuffSize);
                            if (BytesRead > 0) then Stream.Write(Buff,BytesRead);
                            until BytesRead <= 0;
                              Relaxander
                              Использовать цикл нельзя. Так как не будет сообщение о доставки и следовательно и отправка другой порции данных. За раз в сообщение можно читать только один раз.
                              А повторная запись скорее всего тоже блокируется и возвращает 0. Я бы так сделал для предотвращения переполнения внутренних буферов.
                              Сообщение отредактировано: Pavia -
                                Нужно делать автомат состояний.
                                В состояние 0 ждем прием команды на передачу файла
                                в состояние 1 читаем порцию данные, можно сразу писать в файл
                                в состояние 2 информируем о завершение чтения закрываем файл

                                переход из 0 по пришедшей команде
                                переход из 1 во второму по счётчику принятых байт
                                переход из 2 в 0 после отработки логики.


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

                                Точно также с записью.

                                Причем для устойчивости скорее всего придется добавлять терминальные символы в поток. А это значит что надо будет экранировать их в исходном файле.
                                Либо разделять передачу и команды на разные сеансы, порты. Последнее хоть и популярно но снижает производительность.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0.0849 ]   [ 15 queries used ]   [ Generated: 20.09.26, 18:02 GMT ]