[Delphi, Socket] Портится файл при передаче

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by dreamcation, 19 Jul 2010.

  1. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Для передачи файла от сервера к клиенту использую код представленный здесь. Возникло несколько проблем:
    1. После передачи файла появлялась ошибка пока я не убрал строку
    Code:
    MS.Free; // Убиваем буфер
    2. После передачи я нахожу файл, размер которого соответствует исходному, но совершенно не пригодный для прочтения (т.е. он не определяется как музыка, если это был mp3 или не открывается для просмотра если это был jpg).
    Как это можно исправить?
    Если у кого нибудь есть хороший код для передачи файлов через ServerSocket/ClientSocket так же буду очень благодарен.
     
  2. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    код не смотрел но если при освобождении кучи ошибка то значит где то раньше кучу повредил отсюда скорее всего и файл не читаемый получается
    просто я не паскальщик симптомы сишные обычно именно такие она видать при освобождении кучу проверяет и исключение кидает вот и все ищите повреждение кучи чтобы убедится запустите в релизе если все нормально значит отладочный код кучи который следит за ее состоянием вам сообщает что она испорчена
     
    #2 greki_hoy, 19 Jul 2010
    Last edited: 19 Jul 2010
  3. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Вот держи Indy

    Клиент



    Code:
     
    TFileStream * SF = new TFileStream(Form44-> Edit2->Text, Classes::fmCreate);//куда будем сохранять 
     IdTCPClient1->Disconnect();
     IdTCPClient1->Connect();
    SF->Position=0;
     IdTCPClient1->IOHandler->WriteLn("I");
    IdTCPClient1->IOHandler->WriteLn(Edit1->Text)//Путь к файлу на удаленном компе 
    IdTCPClient1->IOHandler->ReadStream(SF,-1,false);
    IdTCPClient1->Disconnect();
       if(SF)
     {
     delete SF;
     SF = NULL;
     }

    Сервер

    Code:
    AnsiString S = AContext->Connection->IOHandler->ReadLn();
    if(S[1]=='I') //пришел сигнал отправить файл
    {
     TFileStream * SF = new TFileStream(AContext->Connection->IOHandler->ReadLn(), Sysutils::fmOpenRead);
     AContext->Connection->IOHandler->Write(SF,0,true);
     delete SF;
     AContext->Connection->Disconnect();//правильнее поставить в __finally
    }

    P.S Будут вопросы пиши , если что могу проэкт готовый отрыть делал когда то
     
  4. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Спасибо! С удовольствием взглянул бы на проект... желательно на Delphi )
     
  5. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Пожалуйста.Делфи к сожалению нету так что токо C++ Builder,смогу дать токо через часика полтора, надо ?
     
  6. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Давай, думаю будет полезно)
     
  7. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Лови, там уже и скомпилированные и исходники делал когда то для себя ) Еси че спрашивай :) http://slil.ru/29480148
     
  8. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    хороший исходник, жаль только не на Delphi и не на сокетах))) придется разбираться)
     
  9. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Это Инди я ж выше сказал ) Да и там все просто )
     
  10. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    да, я знал что будет на Indy. просто серверная часть проекта написана на сокетах, хочется что бы все было в одном стиле)
     
  11. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Хм на инди лучше на сокетах не смошь передать больше 15 мб
     
  12. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    а вот это не хорошо... с чем связано данное ограничение сокетов?
     
  13. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17
    Я наверно не очень правильно сказал , нельзя передавать прямо так , но можно делить по байтам , я читал что лучше передавать по 8192 байт. (вычитал в книжке "NET. Сетевое программирование для профессионалов") В Инди же можно передавать 1 гигабайт прямо так
     
  14. NemeZz

    NemeZz Elder - Старейшина

    Joined:
    20 Aug 2008
    Messages:
    102
    Likes Received:
    67
    Reputations:
    3
    Ты совершенно не в теме. На сокетах можно то же, что и на инди, и даже больше. Т..к инди - это обертка вокруг сокетов. И меньше слушай ерунды
    На send тебе возвращается размер переданного. Если он меньше того, что ты хотел отправить - смещаешь буфер и передаешь дальше. И так до 0 разницы между желаемым и действительным или socket_error -а.
    Правда не многие знают, что send - функция, даже в очень авторитетных кодах часто опускают проверку результата.
     
  15. 0pTik

    0pTik Banned

    Joined:
    18 Jul 2010
    Messages:
    240
    Likes Received:
    85
    Reputations:
    17

    Эммм похоже не в теме ты, мы не о winsock а о стандартных компонентах
     
  16. NemeZz

    NemeZz Elder - Старейшина

    Joined:
    20 Aug 2008
    Messages:
    102
    Likes Received:
    67
    Reputations:
    3
    А смысл в этом компоненте, когда без него можно быстрее и красивее все реализовать? Плюс будешь знать, что если баги - ты знаешь того парня, на которого ругаться, а не на таинственных разработчиков индейцев
     
  17. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Вот то что тебе надо.Клиент-Сервер на сокетах с отправкой сообщений и файлов...
    Качаем...
     
  18. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Artist, премного благодарен! Именно то что искал, и главное что работает! ;-)
     
  19. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Возникла проблема. При использовании кода из исходников выше, получается странная вещь... в моем проекте почему то данные передаются с пробелом после каждого символа. Поясню. Например при отправке текстового файла с текстом "Hello, world!", у клиента образуется файл содержание которого "H e l l o , " (при чем как только что оказалось это не пробелмы, т.к. выделить текст и скопировать сюда не получилось). Приведу кратко код отправки и приема:

    === Отправка ===
    Code:
    procedure TForm1.Button7Click(Sender: TObject);
    var
      Size: Integer; // размерчик
      P: ^Byte; // указатель в память
    begin
      Image1.Picture.SaveToFile('captcha.jpg');
      MS.LoadFromFile('captcha.jpg'); // Загружаем файл в буфер
      // Посылаем информацию о файл (команда # название # размер)
      Server.Socket.Connections[0].SendText('file#' + 't.txt' + '#' + IntToStr(MS.Size) + '#');
      MS.Position := 0; // Переводим каретку в начало файла
      P := MS.Memory; // Загружаем в переменную "P" файл
      ClientSocket1.Socket.SendBuf(P^, MS.Size);             // Посылаем файл
    end;
    === Прием ===
    Code:
    procedure TForm1.Writing(Text: string);
    begin
      if MS2.Size < fSize then // Если принято байт меньше размера файла, то...
        MS2.Write(Text[1], Length(Text)); // Записываем в буфер
      ProgressBar1.Position := MS2.Size * 100 div fSize;
      // Выводим прогресс закачки файла
      if MS2.Size = fSize then // Если файл принят, то...
      begin
        Receive := false; // Переводим клиента в нормальный режим
        MS2.Position := 0; // Переводим каретку в начало буфера
        if not(DirectoryExists(ExtractFilePath(ParamStr(0))
              + '\' + 'Хранилище Файлов')) then
          CreateDir(ExtractFilePath(ParamStr(0)) + '\' + 'Хранилище Файлов');
        MS2.SaveToFile(ExtractFilePath(ParamStr(0))
            + '\' + 'Хранилище Файлов\' + fName); // Сохраняем файл
        Form1.Client.Socket.SendText('/dend');
        // ServerSocket1.Socket.Connections[0].SendText('/dend'); // Посылаем команду "/dend", то есть файл принят
        // mmoMsg.Lines.Add('[Client]::Принят файл ' + fName);     //Запишем в сообщения то что мы приняли файл
      end;
    end;
    
    procedure TForm1.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
    var
      sMessage: string;
    begin
      sMessage := Socket.ReceiveText;
      if Receive then // Если клиент в режиме приёма файла, то...
        Writing(sMessage) // Записываем данные в буфер
      else // Если клиент не в режиме приёма файла, то...
      begin // начинается блок команд
        if Copy(sMessage, 0, Pos('#', sMessage) - 1) = 'file' then
        // Если это файл, то...
        begin
          MS2 := TMemoryStream.Create; // Создаём буфер для файла
          Delete(sMessage, 1, Pos('#', sMessage)); // Определяем имя файла
          fName := Copy(sMessage, 0, Pos('#', sMessage) - 1);
          // Определяем имя файла
          Delete(sMessage, 1, Pos('#', sMessage)); // Определяем размер файла
          fSize := StrToInt(Copy(sMessage, 0, Pos('#', sMessage) - 1));
          // Определяем размер файла
          Delete(sMessage, 1, Pos('#', sMessage)); // Удаляем последний разделитель
          Receive := true; // Переводим сервер в режим приёма файла
          Memo1.Lines.Add('[Client]::Пришел файл ' + fName);
          // запишем в сообщения о том что нам послали файл
          Memo1.Lines.Add('[Client]::Размер Файла ' + IntToStr(fSize));
          // запишем размер файла
          Writing(sMessage); // Записываем данные в буфер
        end
        else
          Memo1.Lines.Add('[Client]:' + sMessage); // нам пришло текстовое сообщение,так заишем же его
      end;
    end;
    
    Что здесь можно подправить, дабы исправить эту ошибку?
     
  20. dreamcation

    dreamcation New Member

    Joined:
    2 Apr 2010
    Messages:
    75
    Likes Received:
    0
    Reputations:
    0
    Еще одна странная вещь... EXE файлы идущие в пример предоставленном Artist прекрасно работали, но после того как я не внося ни каких изменений откомпилировал сервер (принимающую файл сторону) в Delphi 2010 то файлы стали передаваться так же не верно. Вместо "Hello, world!", у клиента образуется файл содержание которого "H e l l o , ". В чем здесь дело?... мне кажется это как то связано с
    Code:
    MS2.Write(Text[1], Length(Text)); // Записываем в буфер