![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Передача данных через сокеты [D6]
delpher_gray © (2002-10-20 17:51:00)Господа Делферы !
Подскажите почему "это" не работает ?
На приём:
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", затем размер картинки, а затем сама картинка.
Файл принемается не до конца... Допишите код, если кто знает как это осуществить...
Song (2002-10-24 11:38:00) [1]Ну и славно. Если Вы бы обратили внимание на мою реплику раньше, давно бы всё написали.
delpher_gray (2002-10-24 11:31:00) [2]Огромное вам спасибо Song !
Я написал прогу, и она отлично работает...
Song (2002-10-23 22:11:00) [3]ЕЩЁ РАЗ ГОВОРЮ ПОЧЕМУ: (я уже говорил об этом в другом Вашем топике)
потому_что_MS_локальная_переменная
Она обнуляется при каждом возникновениисобытия TServerSocket.onClientRead
delpher_gray (2002-10-23 19:50:00) [4]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 16:17:00) [5]Забыл добавить что в 3 пункте сервера после того как файл запишем передаём команду на вызывающий хост, получив которую последний поднимет флажок Flag, благодаря чему вызывающий клиент выйдет из цикла и только потомзакроет сокет.
Song (2002-10-23 16:15:00) [6]Я говорю Вам, что всё работает и по Вашему вышеиложенному алгоритму только нужно довести до ума.
Вот примерный алгоритм:
Клиент:
1. Клиент посылает строку "header#file.txt#100#End"
2. Клиент посылает файл потоком
3. Инициирует цикл ожидания пока, например переменная Flag не станет True
4. Конец работы клиента
Сервер:
1. Сервер ловит данные. Проверяет есть ли "header".
2. Если нет, переходим на третий шаг. Если есть значит, это название файла. Создаёт в памяти экземпляр класса TMemoryStream (глобального для данного модуля) и заносит в переменную Limit например длину файла - 100 байт. Вырезает из строки начало до слова End включительно. Переходим на третий шаг.
3. Добавляем к экземпляру TMemoryStream полученную строку данных. Проверяем, не равно ли длина экземпляра переменной Limit. Если равно записываем поток в файл, уничтожаем экземпляр. Если не равно ничего не делаем, выходим из процедуры.
Вот и всё. Работает данный алгоритм стабильно. Сам делал.
delpher_gray (2002-10-23 15:50:00) [7]Ну тогда подскажите как можно написать подобную прогу ?
delpher_gray (2002-10-22 15:07:00) [8]Ммммм да... =/
И что же мне делать ??
Мне как-то нужно доделать этот код.
Ну как-нибудь можно же написать подобную прогу ?
grvakh (2002-10-22 14:06:00) [9]На прием стоит - data.write
Где вообще data связывается с сокетом?
YouNick (2002-10-22 13:47:00) [10]2Delpher_gray: Никак ... :(
Знаешь такой термин "конечный автомат"?
Вот для разбора принятых данных нужно создать что-то похожее.
Ведь ты в клиенте отправляешь один пакет (клиентская программа), а реально в сеть может уйти несколько пакетов (TCP их сам разбивает на реальные пакеты). Например, ты отправляешь 10000 байт одним пакетом, а принять можешь 10 пакетов по 1000 байт. Что в таком случае считать "командой"? И первый знак в твоей команде может совпасть с содержимым файла - "f". ТОгда ты в файл такого позаписываешь .... ;))) У мню где-то были классы, реализующие передачу файлов (серверная и клиентская часть), надо поискать. Если конечно интересует еще ;)
delpher_gray (2002-10-22 13:01:00) [11]Господа Делферы !
Я наконец-то понял как заставить эту прогу работать...
Вот так:
1. Сначала от клиента идёт команда серверу "send".
2. Когда сервер примет команду, он посылает: "b"+Размер файла+"Сам файл".
3. Если клиенту приходит эта команда, то он отделяет размер и записывает его в переменную DataSize, а сам файл пошет в Data (TMemoryStream).
В одном пакете не может же уместиться весь файл, нужно принять несколько пакетов... А вот чтоб определить что это кусок файла, а ни какая-нить команда, нужна как-то пометить пакеты (дописать перед пакетом "f").
Если вы подскажите как можно пометить пакеты, тогда нужно дописать:
4. Если в команде первый знак "f", то просто дописываем в Data кусок файла...
Вот так можно осуществить то что я зудумал ;-)
Но для этого нужно пометить пакеты...
Жду ответов, заранее благодарен.
Song (2002-10-22 11:38:00) [12]Инфа всегда_по_сети_передаётся_пакетами независимо от того какого размера файл (ну если только файл меньше размера пакета). Поэтому проблема не в том.
delpher_gray (2002-10-22 11:27:00) [13]!!!!!!!!!!!
to Song
Это не работает потому что инфай передаётся не в одном пакете, а в нескольких... Кажется я нашёл ошибку ;-)))
Я попробую дописать эту прогу, но если что-то будет не получатся, то ждите следующего вопроса !
Song (2002-10-21 15:56:00) [14]Не работает потому что не успевает передаться. Надо после SendStream() ждать команды от противоположного сокета, о том что файл принят и только после этого делать Socket.Close
Я тоже когда начинал делать переправку между клиентами файлами и сообщениями взял за пример этот отрывок из FAQ, но потом когда всё довелось до ума, от него мало чего осталось :-)
delpher_gray (2002-10-21 15:48:00) [15]to Song.
Даже очень напоминает :-)
Я просто хочу сделать так, чтоб файл не путался с другими командами...
Song (2002-10-21 13:34:00) [16]Напоминает переделанный пример из FAQ..
delpher_gray (2002-10-21 11:17:00) [17]Попробую...
Polevi (2002-10-20 19:51:00) [18]очень советую ВНИМАТЕЛЬНО почитать хелп на WSAAsyncSelect