Способы передачи файлов по сети. Кроссплатформенно.

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение stikriz » 07.06.2012 11:13:48

Почему бы не написать сервис/демон и посредством сокетов не передавать и обрабатывать как вздумается?
SQL сервер, например FireBird - это мн-о-о-о-о-гоплатформенное решение, единое, без сторонних зависимостей в виде денег, зависимости от платформы, зависимости от зависимостей :-) В общем, риски минимальны.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 11:33:24

Есть вариант запилить на базе LHTTPServerComponent, только опять же доки нету, как ему назначить DocROOT даже не понятно. Но по идее, как раз из DocROOT можно было бы качать нужные мне файлы..

Добавлено спустя 2 минуты 11 секунд:
stikriz писал(а):Почему бы не написать сервис/демон и посредством сокетов не передавать и обрабатывать как вздумается?


Да я бы запилил, только документации никак не могу найти в стиле "как передать через сокет файл в компоненте LNet". Написал разработчику вопрос из разряда "текст ты показал как пересылать, а что такое aData и что ты имел ввиду вообще?"
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение stikriz » 07.06.2012 12:13:37

Все, что нужно от сокета - уметь передавать буфер байтиков. Передаешь размер в байтиках, потом пихаешь по TCP байтики из файла. Сервер принимает размер, и читает столько байтиков из TCP, столько ты передал, попутно пихая их в файл. Потом работает с файлом. Потом все в точности до наоборот. Потом, клиент закрывает соединение. Все.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 12:28:37

То есть читать из файла нетипизированного и писать так же.. Надо попробовать таую штуку намутить. Щааа...
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение vada » 07.06.2012 13:31:27

Я раздавал.
На сервере: SQL <--> Tomcat + моя приблуда <--> SMTP/POP3
На клиенте: Почтовый клиент

Но вам сторонние зависимости не подходят, да и файлы у меня были до 2 метров.
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение Brainenjii » 07.06.2012 14:11:32

через indy - никаких проблем не было. Сейчас решил накидать маленький примерчик с lnet'ом - УЖЕ 3 ЧАСА БЬЮСЬ, КАКОЙ $#@%!!#!@ ТАКОЕ ПРИДУМАЛ!!! Какие-то OnCanSend, в которые НИКОГДА не заходит, c нормальным отправлением - после 65 Кб - send buffer full, try again later?!!! WTF!!!!
Кто пробовал - помогите примером, а то с ума щас сойду ^_^

Добавлено спустя 2 часа 10 минут 1 секунду:
всё, нафиг ^_^ Мозг взорван, рабочий день потерян, я сдаюсь >_<
Код сервера: http://pastebin.com/VLvNGpeR
Код клиента: http://pastebin.com/9BqrpxKF
Сервер просто запускается, клиент стартует с параметрами:
<projectname> PUT /path/to/file - чтобы закачать файл на сервер
<projectname> GET file - чтобы скачать файл с сервера

Закачка файла с клиента на сервер работает без нареканий, при загрузке с сервера на клиент последний буфер ЗАРАЗА ТАКАЯ УХОДИТЬ НЕ ХОЧЕТ НИ В КАКУЮ!!!!!11111разраз
Код вроде практически идентичный. Сервер уверяет, что всё отправлено. Клиент стабильно не находит последний буфер с данными, если в один файл не влез. Такое ощущение, что он его и не ждёт, но как его заставить я не представляю...
Буду счастлив, если мне объяснят, где я дурак ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 16:40:54

Brainenjii писал(а):через indy - никаких проблем не было

Я так понял, что прикручивание самого Indy - задача не самая тривиальная. И будет ли оно кроссплатформенным тоже сильно не факт. По поводу буфера, автор пишет так в своём блоге:

How do I send big chunks of data like files?

You can send big chunks by using the “ping-pong” principle. There are 2 events you need to understand first namely OnError and OnCanSend.

OnError is the most obvious one, it tells you that some error occured. It is important to watch this one when sending too because sends can fail with network errors (connection reset, timeout etc.).

OnCanSend is usually misunderstood. It’s the event which gets fired whenever you can send data AGAIN. This means that you first need to get to the state, when sending data is no longer possible (due to the OS buffer being full). This can be done by sending too much data too fast. How do you know it happened? If .Send or .SendMessage returns 0, and no OnError got called, you filled the OS send buffers and need to wait a bit. The OnCanSend event will tell you when you can continue sending.

So here’s how to best do sending. I’m using a “function GetNewChunk(): string” for imaginary function/method which returns a string of up to 65535 bytes (the usual max send size defined by OS). This function should either read from file or some other source you want to send from.

procedure TMyClass.OnCanSend(aSocket: TLSocket);
var
Sent: Integer; // number of bytes sent each try
TempBuffer: string = ''; // our local temp. buffer for the filestream, can be done smarter tho
begin
repeat
if Length(TempBuffer) = 0 then
TempBuffer := GetNewChunk; // get next chunk if we sent all from the last one
Sent := FConnection.SendMessage(TempBuffer, aSocket); // remember, don't use the aSocket directly!
Delete(TempBuffer, 1, Sent); // delete all we sent from our temporary buffer!
until (Sent = 0) or (AllIsSent); // try to send until you can't send anymore
end;

So basically, this handler will try to send in a loop until it can’t send anymore or there’s no more data to send. So how do you start sending then? I mean OnCanSend doesn’t get fired by lNet until you CAN’T send anymore.. well it’s simple. Just call the OnCanSend with the appropriate socket! But which socket you ask? Well if you’re a basic TCP client, then it’s simple, just the Iterator. If you’re a server, you need to know on which socket you want to send anyway.

But how come this sends the whole thing? What happens is this. You first call the OnCanSend handler yourself, ensuring that either everything is sent in one go, or that you sent so much that the OS buffer got filled up. If so then OnCanSend will get automagically called by lNet again when sending is possible. This way you end up with a kind of “ping-pong” style and all data gets sent when possible.


То есть, надо пересылать данные кусочками по 64Kb. Иначе буфер ОС порежет, библиотеку абстрагироваться никто не учил.

Вот ответ самого разработчика LNet о способе работы с Send\Get вместо SendMessage\GetMessage:

Тема: Re: LNet
Дата: Thu, 7 Jun 2012 09:46:26 +0200
От: Ales Katona
Кому: evgeny_veresk


aData is an untyped parameter. It's basically a pointer to anything (but you don't add @ before the variable).

For example if you have an array of byte like: myArray: array[0..100] of byte; you would send like:

lTCP.Send(myArray[1], length(myArray, aSocket);

Notice I used array[1] as the data argument because array[1] is where the real data starts and has 100 bytes length. Sending a record is more straightforward (you just do send(record, sizeof(record)));

Same goes for GET. You can get more info about this type of argument in the free pascal reference book.

Ales
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение stikriz » 07.06.2012 17:02:05

Brainenjii писал(а):Закачка файла с клиента на сервер работает без нареканий, при загрузке с сервера на клиент последний буфер ЗАРАЗА ТАКАЯ УХОДИТЬ НЕ ХОЧЕТ НИ В КАКУЮ!!!!!11111разраз


Надо закрыть сокет. Да, это хрень. Можно попробовать докопаться до хандла и:
varOpt: Integer;
...
begin
Opt:=1;
fpsetsockopt(ClientSocket.SocketHandle, IPPROTO_TCP, TCP_NODELAY, PChar(@Opt), Sizeof(Opt));
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение Brainenjii » 07.06.2012 17:11:49

Ммм? Можно чуть-чуть поподробней? ^_^ Я никогда не работал с сокетами ниже Indy так что подобный код вызывает у меня духовный трепет ^_^
Последний раз редактировалось Brainenjii 07.06.2012 17:22:08, всего редактировалось 1 раз.
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение stikriz » 07.06.2012 17:20:10

Это установка опции сокета, чтобы он не ждал, когда буфер заполнится полностью, чтобы послать клиенту. Я с Инди не работал. Там где-то должен быть реальный сокет - поискать функцию fpsocket или просто socket и посмотреть куда девается хандл.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 17:54:13

Если получится, опубликуй функции для приёма и для отправки файла. Только с комментариями, без комментариев я вообще ничерта не понимаю, что понаписано.

Добавлено спустя 2 часа 29 минут 12 секунд:
Ну что, заработало? Я только что до IDE добрался, будем мучать систему.
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение Brainenjii » 07.06.2012 22:06:25

все прекрасно работает на передачу от клиента к серверу, и НЕПОЙМИ КАК - от сервера к клиенту... Файл в 700 Мб передался без проблем, md5 совпало, зато 19Кб - фиг...
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 22:09:54

Код, батенька, код покажи, плиииз! Только с комментами.
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение Brainenjii » 07.06.2012 22:12:38

http://pastebin.com/VLvNGpeR - сервер, http://pastebin.com/9BqrpxKF - клиент. Комментарии, конечно, попробую написать, но всю жизнь считал свой код самодостаточным по информативности ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Способы передачи файлов по сети. Кроссплатформенно.

Сообщение veresk » 07.06.2012 22:24:12

Brainenjii писал(а):но всю жизнь считал свой код самодостаточным по информативности ^_^

Я не программист уже давным давно и вряд ли когда-то им был по-нормальному. Сделайте скидку! :-)

Добавлено спустя 1 минуту 52 секунды:
У меня пока что всё виснет в таком состоянии:

Код: Выделить всё
function TForm1.SendFile (filename: string; remote_ip: string; remote_port: word): boolean;
var
  binfile: file;
  i: int64;
  buf: byte;
  TCP: TLTCPComponent;
begin
     TCP.Create(Form1);
     TCP.Port:=remote_port;
     TCP.Host:=remote_ip;
     AssignFile (binfile, UTF8ToSys(filename));
     Reset(binfile,1);
       For i:=1 to FileSize(UTF8ToSys(filename)) do
           begin
              BlockRead(binfile,buf,1);
              TCP.Send(buf, 1);
           end;
       label2.Caption:=label2.Caption+ ' ' + IntTostr(i);
     CloseFile(binfile);
end;


Явно где-то надо обработку исключений вставить, так как клиента на "той стороне" ещё нету.
veresk
новенький
 
Сообщения: 48
Зарегистрирован: 31.01.2012 12:23:32

Пред.След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 229

Рейтинг@Mail.ru