Форум: "Сети";
Текущий архив: 2002.12.19;
Скачать: [xml.tar.bz2];
Вниз
Передача данных через сокеты Найти похожие ветки
← →
delpher_gray (2002-10-20 17:51) [0]Господа Делферы !
Подскажите почему "это" не работает ?
На приём:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
s, sl: string;
begin
s:= Socket.ReceiveText;
if s[1] = "b" then
begin
Delete(s, 1, 1);
if not Reciving then
begin
SetLength(sl, StrLen(PChar(s))+1);
StrLCopy(@sl[1], PChar(s), Length(sl)-1);
DataSize:= StrToInt(sl);
Data:= TMemoryStream.Create;
Delete(s, 1, Length(sl));
Reciving:= true;
end;
try
Data.Write(s[1], length(s));
if Data.Size <= DataSize then StatusBar.SimpleText := "Принято "+IntToStr(Data.Size)+" из "+IntToStr(DataSize);
if Data.Size = DataSize then
begin
Data.Position:= 0;
Image2.Picture.Bitmap.LoadFromStream(Data);
Data.Free;
Reciving:= false;
Socket.Close;
end;
except
Data.Free;
end;
end;
end;
На передачу:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
ms: TMemoryStream;
begin
if Socket.ReceiveText = "send" then
begin
ms:= TMemoryStream.Create;
try
Image1.Picture.Bitmap.SaveToStream(ms);
ms.Position:= 0;
Socket.SendText("b"+IntToStr(ms.Size) + #0);
Socket.SendStream(ms);
except
ms.Free;
end;
end;
end;
Тут сначала посылается знак "b", затем размер картинки, а затем сама картинка.
Файл принемается не до конца... Допишите код, если кто знает как это осуществить...
← →
Polevi (2002-10-20 19:51) [1]очень советую ВНИМАТЕЛЬНО почитать хелп на WSAAsyncSelect
← →
delpher_gray (2002-10-21 11:17) [2]Попробую...
← →
Song (2002-10-21 13:34) [3]Напоминает переделанный пример из FAQ..
← →
delpher_gray (2002-10-21 15:48) [4]to Song.
Даже очень напоминает :-)
Я просто хочу сделать так, чтоб файл не путался с другими командами...
← →
Song (2002-10-21 15:56) [5]Не работает потому что не успевает передаться. Надо после SendStream() ждать команды от противоположного сокета, о том что файл принят и только после этого делать Socket.Close
Я тоже когда начинал делать переправку между клиентами файлами и сообщениями взял за пример этот отрывок из FAQ, но потом когда всё довелось до ума, от него мало чего осталось :-)
← →
delpher_gray (2002-10-22 11:27) [6]!!!!!!!!!!!
to Song
Это не работает потому что инфай передаётся не в одном пакете, а в нескольких... Кажется я нашёл ошибку ;-)))
Я попробую дописать эту прогу, но если что-то будет не получатся, то ждите следующего вопроса !
← →
Song (2002-10-22 11:38) [7]Инфа всегда_по_сети_передаётся_пакетами независимо от того какого размера файл (ну если только файл меньше размера пакета). Поэтому проблема не в том.
← →
delpher_gray (2002-10-22 13:01) [8]Господа Делферы !
Я наконец-то понял как заставить эту прогу работать...
Вот так:
1. Сначала от клиента идёт команда серверу "send".
2. Когда сервер примет команду, он посылает: "b"+Размер файла+"Сам файл".
3. Если клиенту приходит эта команда, то он отделяет размер и записывает его в переменную DataSize, а сам файл пошет в Data (TMemoryStream).
В одном пакете не может же уместиться весь файл, нужно принять несколько пакетов... А вот чтоб определить что это кусок файла, а ни какая-нить команда, нужна как-то пометить пакеты (дописать перед пакетом "f").
Если вы подскажите как можно пометить пакеты, тогда нужно дописать:
4. Если в команде первый знак "f", то просто дописываем в Data кусок файла...
Вот так можно осуществить то что я зудумал ;-)
Но для этого нужно пометить пакеты...
Жду ответов, заранее благодарен.
← →
YouNick (2002-10-22 13:47) [9]2Delpher_gray: Никак ... :(
Знаешь такой термин "конечный автомат"?
Вот для разбора принятых данных нужно создать что-то похожее.
Ведь ты в клиенте отправляешь один пакет (клиентская программа), а реально в сеть может уйти несколько пакетов (TCP их сам разбивает на реальные пакеты). Например, ты отправляешь 10000 байт одним пакетом, а принять можешь 10 пакетов по 1000 байт. Что в таком случае считать "командой"? И первый знак в твоей команде может совпасть с содержимым файла - "f". ТОгда ты в файл такого позаписываешь .... ;))) У мню где-то были классы, реализующие передачу файлов (серверная и клиентская часть), надо поискать. Если конечно интересует еще ;)
← →
grvakh (2002-10-22 14:06) [10]На прием стоит - data.write
Где вообще data связывается с сокетом?
← →
delpher_gray (2002-10-22 15:07) [11]Ммммм да... =/
И что же мне делать ??
Мне как-то нужно доделать этот код.
Ну как-нибудь можно же написать подобную прогу ?
← →
delpher_gray (2002-10-23 15:50) [12]Ну тогда подскажите как можно написать подобную прогу ?
← →
Song (2002-10-23 16:15) [13]Я говорю Вам, что всё работает и по Вашему вышеиложенному алгоритму только нужно довести до ума.
Вот примерный алгоритм:
Клиент:
1. Клиент посылает строку "header#file.txt#100#End"
2. Клиент посылает файл потоком
3. Инициирует цикл ожидания пока, например переменная Flag не станет True
4. Конец работы клиента
Сервер:
1. Сервер ловит данные. Проверяет есть ли "header".
2. Если нет, переходим на третий шаг. Если есть значит, это название файла. Создаёт в памяти экземпляр класса TMemoryStream (глобального для данного модуля) и заносит в переменную Limit например длину файла - 100 байт. Вырезает из строки начало до слова End включительно. Переходим на третий шаг.
3. Добавляем к экземпляру TMemoryStream полученную строку данных. Проверяем, не равно ли длина экземпляра переменной Limit. Если равно записываем поток в файл, уничтожаем экземпляр. Если не равно ничего не делаем, выходим из процедуры.
Вот и всё. Работает данный алгоритм стабильно. Сам делал.
← →
Song (2002-10-23 16:17) [14]Забыл добавить что в 3 пункте сервера после того как файл запишем передаём команду на вызывающий хост, получив которую последний поднимет флажок Flag, благодаря чему вызывающий клиент выйдет из цикла и только потом закроет сокет.
← →
delpher_gray (2002-10-23 19:50) [15]Song !
Я написал прогу так как Вы объяснили, но там если первые 4 символа не равны "file", то прога выдаёт ошибку...
Вот код сервера:
unit UServer;
Подскажите где я ошибся ;-)
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, ComCtrls;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
StatusBar: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Open;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
MS: TMemoryStream;
S: string;
Sp: string;
Name: string;
Size: integer;
label Receive;
begin
S := Socket.ReceiveText;
Sp := Copy(S, 1, 4);
if Sp <> "file" then goto Receive;
if Sp = "file" then
begin
Delete(S, 1, 5);
Name := Copy(S, 1, Pos("#", S) -1);
Delete(S, 1, Length(Name) +1);
Size := StrToInt(Copy(S, 1, Pos("#", S) -1));
Delete(S, 1, Length(IntToStr(Size)) +4);
MS := TMemoryStream.Create;
Receive:
MS.Write(S[1], Length(S));
StatusBar.SimpleText := "Принято "+IntToStr(MS.Size)+" из "+IntToStr(Size);
if MS.Size = Size then
begin
MS.Position := 0;
MS.SaveToFile(Name);
Socket.SendText("end");
ServerSocket1.Close;
MS.Free;
end;
end;
end;
end.
← →
Song (2002-10-23 22:11) [16]ЕЩЁ РАЗ ГОВОРЮ ПОЧЕМУ: (я уже говорил об этом в другом Вашем топике)
потому_что_MS_локальная_переменная
Она обнуляется при каждом возникновении события TServerSocket.onClientRead
← →
delpher_gray (2002-10-24 11:31) [17]Огромное вам спасибо Song !
Я написал прогу, и она отлично работает...
← →
Song (2002-10-24 11:38) [18]Ну и славно. Если Вы бы обратили внимание на мою реплику раньше, давно бы всё написали.
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2002.12.19;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.013 c