Форум: "Сети";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];
ВнизБанальное: передача файла с помощью TServerSocket & TClientSocket Найти похожие ветки
← →
VID (2003-11-10 15:13) [0]Сабж - это основная идея создания программы.
Посколько с TServerSocket в режиме ThreadBlocking я ещё никогда не работал (был опыт работы с этим компонентом в режиме NonBlocking, да и то больше года назад), возникает куча вопросов связанных с этим.
Итак, как видно из названия ветки, я хочу написать программу по передаче файлов от клиента серверу и наоборот. Хотелось бы узнать как лучше изначально реализовать как бы выразиться... стандарт передаваемых пакетов что ли..
т.е. хотелось бы понять какая должна быть структура передаваемых пакетов данных (в данном случае под пакетами я понимаю передаваемые данные, соответствующие какой-то определённой структуре, понятной серверу и клиенту),
и как, например, можно реализовать одновремменною передачу файла (допустим от клиента к серверу), и передачу других данных (например какую нибудь команду), от того же клиента тому же серверу. В частности у меня возникает вопрос, как серверу определять какие данные приходящие от клиента относятся к передаваемому файлу а какие к независимым сообщениям(командам).
В общем, то это всё вопросы алгоритмические, и до проблем которые будут на практическом этапе я ещё не дошёл, торопиться не хочу, т.к. программа по-сути нужна только мне, да и задумал я всё это лишь для того что бы научиться всё-таки работать с TServerSocket в ThreadBlocking-режиме.
Поэтому было бы неплохо, если Вы указали бы линки на ресурсы в интернете по теме правильного создания серверов такого типа.
Помниться был один такой линк, но там шло описание сокетов, во-первых, с примерами на языке С++ (которого я не знаю), и соотв-но там не было ни слова о VCL и связанного с этим TServerSocket. Так вот, такого не надо, хотелось бы увидеть связанную именно с VCL статью, и к тому не глобального и всеобъемлещего характера "что бы сразу второй ICQ-сервер написать", а именно по теме, что называется коротко и ясно :)
Жду ответов... заранее спасибо всем кто откликнется
← →
VID (2003-11-11 19:11) [1]Да ладно, кто то же может помочь :)
← →
Tik (2003-11-11 19:16) [2]Скопировать файл. (Eshko 11.11.03 18:57) ----------Посмотри !!!
← →
Digitman (2003-11-12 08:44) [3]какое отношение вопрос о прикладном протоколе инф.обмена имеет к транспортным протоколам ? и, тем более, к одно- или мультипоточности вычислительных процессов ?
никакого.
мухи - отдельно, котлеты - отдельно.
← →
Fredericco (2003-11-12 12:21) [4]Тут есть два варианта:
1) Данные будут передоваться друг за другом. Например: из А в В ты хочешь передать файл. В стоит в режиме приема комманд. Посылаешь комманду В (формат тут какой захочешь), в которой указываешь длину в байтах передоваемого файла и любую другую инфу. При приеме такой комманды на В с А, В для А переходит в режим приема файла, принимает все байтики в размере указанном ранее (опционально: сообщает А что файл принят) и переходит опять в режим приема комманд.
Плюсы: высокая скорость передачи файла.
Минусы: трудно отслеживать обрыв линнии, придется рассчитывать прогрес приема файла и исходя из этого предполагать временной тйамаут, в течении которого продолжать работать в режиме приема файла. Труднее реализовывать процент передачи на отправляющей стороне.
2) Похож на вариант (1), но резать файл на куски, и передовать порциями. Например: В А разбиваем, скажем 1 000 байтный файл, на 10 кусочков по 100 байт и отправляем так: комманда из А в В с указанием длины файла, В переходит в режим приема файла, принимает указанную длину, рапортует в А об успешном принятии блока данных, переходит в режим приема комманд и по новой.
Минусы: низкая скорость передачи данных.
Плюсы: Возможность в процессе передачи файла передать еще какую-нибудь комманду не относящуюся к передаче файла. Все то, что в минусах у (1).
← →
Polevi (2003-11-12 18:25) [5]type
TPacket=class(TPersistent)
procedure Invoke;virtual;abstract;
end;
TCommandPacket=class(TPacket);
procedure Invoke;override;
end;
TDataPacket=class(TPacket);
procedure Invoke;override;
end;
научись передавать ОБЪЕКТ и вызывай TPacket.Invoke, реализация которого зависит только от твоей фантазии
← →
VID (2003-11-12 22:00) [6]To Tik: Это ведь не много не по теме, что ты показал
To Digitman: всё философствуешь ;)
To Fredericco (and all): А что если сделать так: сначала клиент соединяется с сервером, и создаётся так называемое главное соединение. а когда клиенту надо передать файл, либо получить файл, он инициирует вторичное соединение с сервером, а по сути создаётся ещу один TClientsocket который соединяется с сервером только для того что бы получить/принять файл, и соединение будет разорвано сразу же после выполнения этой операции, ну а главное соединение, для того что бы управлять вторичным, всегду будет знать его Socket:Integer (эту инфу сервер сообщит главному соединению). В случае применения паролей, необходимых для коннекта к серверу, вторичное соединение будет использовать туже комбинацию ЛОГИН/ПАРОЛЬ, что и главное соединение, но только после коннекта кинет команду серверу о своём "вторичном" происхождении...
меня интересует, так вообще делают или это чушь, ненужная ? ;)
to Polevi: даже сказать нечего, а что за Invoke что вообще предполагается за ней (я понимаю, что реализация зависит от моей фантазии, но почему тогда всего лишь одна процедура INVOKE а не INVOKE1, Invoke2, etc?) ?
← →
Digitman (2003-11-13 10:06) [7]
> VID
> всё философствуешь
а как же ?) без нее, философии-то, - никуда) .. и, знаешь, мне ведь помогает "философия" эта, и хорошо помогает, смею тебя заверить)..
а вот тебе уж сколько раз говорил я : не меси в одну кучу мухи и котлеты ! сразу анализируй и дели задачу на функционально, концептуально и логически определенные-завершенные подзадачи ! не внемлешь ведь по прежнему) ... от того и каша в голове и проблемы эти)
код.потоки ? это просто организация выч.процесса, не важно какого ! гнезда там или еще чего - НЕ ВАЖ-НО !! вот так, и не более того !
блок.режим чего-то ? рассматривай это в контексте просто некоего абстрактного выч.процесса, происходящего в некоем абстрактном код.потоке, когда вызванная в этом потоке ф-ция в зависимости от режима (блок. или неблок.) либо блокирует дальнейшее выполнение до момента возврата из ф-ции либо тут же возвращает управление вызвавшему коду ..
транспорт ? рассматриваешь конкретно реализуемый тем или иным компонентом , в случае TServerSocket/TClientSocket - это TCP ...
протокол инф.обмена ? опять же - сам по себе сначала рассматриваешь, без привязки к конкретному транспорту : структуры, порядок обмена ими и пр. и пр.
пойми : ничегоь хорошего-путного не получится, пока каждую отдельную подзадачу ты не будешь представлять в голове совешенно четко и независимо от других подзадач !
← →
Polevi (2003-11-13 10:06) [8]VID © (12.11.03 22:00) [6]
объект - как метод, вх. и вых. параметры его - паблишед свойства объекта, доступные в инвоке
← →
Новичек (2003-11-13 12:42) [9]Вообщето вопрос про клиент-серверные приложения через сокеты очень серьезный!
И новичкам очень тяжело разобраться с етим!
> Digitman
Обьясни структуру организации такого приложения!
А именно:
Есть сервер, есть много клиентов, которые коннектяться к серверу!
Сервер их впускает на себя по логину и паролю!
Как сделать чтоб сервер мог коннектить к себе клиентов, при етом мог "одновременно" работать уже с существующими?.
А именно передавать/принимать файлы и другую информацию (текст, некие управляющие команды и тд)!
Проблем в хорошей организации такого приложения куча:
А имеено:
- Как достовериться на 100% что клиент (сервер) получили файл или другую информацию?
- Как определить что связь разорвана с сервером (клиентом) по различным причинам!...Причины могут быть разными! (Обрыв на линии!,.. Свет глючит и тд!,.) Нужен сам факт что связи уже с ним нету!
- Как одновременно работать с многими клиентами, при етом успевать еще принимать новый коннектяшихся?
- Как сделать чтоб клиенты (и сервер) не "зависали" например при передачи больших файлов и тд?
- Как коректно отключить клиента и как корректно отключиться от сервера?
- Как сделать возможность гонять файлы не через сервер, если надо, а например что сами клиентские машины между собой организовывали етот процесс, если ето возможно (например если находяться в одной и той же локалке!). При етом чтоб управляющий процесс контролировался сервером!
И тд!
Таких вопросов куча!
Модераторам:
Можно было вообще такие вопросы занести в отдельный раздел! Они возникают каждую неделю и никто толком не знает как с етим работать!,.Может занести ето в отдельный раздел, где бы люди разработали общий некий код и больше не подымали подобные вопросы! Я понимаю что для ВАС такие вопросы "глупые", но люди хотят разобраться! А новички больше бы не мучали бы ВАС об елементарном! Ведь посмотрите - на форуме больше 50% вопросы такого типа: "Как узнать айпи адрес?" , "Как узнать макадресс?", "Как работать с сокетами?" , "Как просканировать всю сеть и найти все компьютеры в сети?" , "Как зная имя компьютера получить его айпи и как наоборот?" и тд!,. конечно в статьях есть частичные ответы на некоторые вопросы, но ОНИ честно говоря плохо расписаны!
Спасибо за внимание!
Надеюсь на помощь!
← →
VID (2003-11-13 13:46) [10]To Digitman: На теоретическом уровне я уже более-менее разобрался. Посколько я собираюсь научиться работать именно с TServerSocket то буду говорить о нём.
Я знаю что в режиме ThreadBlocking для каждого нового клиента, сервер создаёт во-первых гнездо (endpoint of the connection to the client - кажется так пишется об этом в HELP"е) и поток, который будет обслуживать клиента, слушать его, отправлять ему данные и тп.
Я выделил три независимые части клиент-сервероного приложения:
1. Транспорт - TServerSocket,TClientSocket
2. Данные - протокол информационного обмена, точнее структура которую указал POLEVI
3. Кодовый поток - код, который работает в отдельном потоке, запускаемом для каждого клиента, и обслуживающий этого клиента.
To All: Теперь же мне надо увидеть всё это в дейсвтии своими глазами, увидеть код, готового ПРОСТОГО клиент-сервероного приложения, где сервер работает в режиме ThreadBlocking а клиент в Blocking-режиме.
Вот я и прошу сейчас: кто может мне скинуть на VidSnap@mail.ru такой пример приложения ?
Кстати, я смотрел исходники Borland Server Socket, но их простыми навать нельзя (как минимум с моей точки зрения).
← →
Digitman (2003-11-13 14:59) [11]
> я смотрел исходники Borland Server Socket, но их простыми
> навать нельзя (как минимум с моей точки зрения).
ничего там сложного нет, не выдумывай) ... все просто и наглядно там
а если ты не привык к анализу чужого кода в первую очередь с т.з. концептуальной, то - извини - никакой "ПРОСТОЙ ПРИМЕР", делающий хоть что-то сколь-либо серьезное, тебе не поможет
если же ты испугался интерфейсов, то так и скажи, а не мудли, иол, сложно) ... впору бросить все это чатотворчество, садиться за книжки и вникать в суть интерфейсов
← →
Digitman (2003-11-13 15:03) [12]
> Новичек
куча вопросов) ... и как всегда - каша, каша ..
задавай по одному в порядке поступления и в отдельных ветках ... постараюсь навести порядок в твоей голове)... ну и мастера, надеюсь, помогут мне
← →
Polevi (2003-11-13 16:13) [13]unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp;
type
TForm1 = class(TForm)
ss: TServerSocket;
procedure ssGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TT=class(TServerClientThread)
protected
procedure ClientExecute;override;
end;
TPacketClass=class of TPacket;
TPacket=class(TPersistent)
public
function Invoke:TPacket;virtual;abstract;
function Serialize:string;
procedure DeSerialize(ANode: OleVariant);
end;
TSumRequest=class(TPacket)
private
FA,FB:integer;
public
function Invoke:TPacket;override;
published
property A:integer read FA write FA;
property B:integer read FB write FB;
end;
TSumResponse=class(TPacket)
private
FSum:integer;
public
function Invoke:TPacket;override;
published
property Sum:integer read FSum write FSum;
end;
← →
Polevi (2003-11-13 16:14) [14]var
Form1: TForm1;
implementation
uses ComObj, ActiveX, TypInfo;
{$R *.dfm}
procedure TForm1.ssGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
SocketThread:=TT.Create(false,ClientSocket);
end;
{ TT }
procedure TT.ClientExecute;
function WaitRequest:string;
var
Buffer:PChar;
bytesRead:integer;
const
BufSize:integer=8192;
EndOfRequest="</PACKET>"#13#10;
begin
Result:="";
GetMem(Buffer,BufSize+1);
try
while true do
begin
bytesRead:=ClientSocket.ReceiveBuf(Buffer^,BufSize);
if bytesRead=-1 then RaiseLastOSError;
Buffer[bytesRead]:=#0;
Result:=Result+Buffer;
if Length(Result)>BufSize then
raise Exception.Create("Invalid data packet");
if Copy(Result,Length(Result)-Length(EndOfRequest)+1,Length(EndOfRequest))=EndOfRequest then
break;
end;
finally
FreeMem(Buffer);
end;
end;
procedure SendResponse(AResponse:string);
var
Buffer:PChar;
bytesSend,bytesLeft:integer;
begin
Buffer:=PChar(AResponse);
bytesLeft:=Length(AResponse);
while bytesLeft>0 do
begin
bytesSend:=ClientSocket.SendBuf(Buffer^,bytesLeft);
if bytesSend=-1 then RaiseLastOSError;
Inc(Buffer,bytesSend);
Dec(bytesLeft,bytesSend);
end;
end;
var
msxml,node:OleVariant;
request,reqClassName:string;
req:TPacket;
begin
CoInitialize(nil);
try
try
msxml:=CreateOleObject("Msxml2.DOMDocument.3.0");
msxml.async:=false;
while not Terminated and ClientSocket.Connected do
begin
request:=WaitRequest;
msxml.loadXML(request);
if msxml.parseError.reason<>"" then
raise Exception.Create(msxml.parseError.reason);
node:=msxml.documentElement.selectSingleNode("//PACKET");
reqClassName:=node.getAttribute("TYPE");
req:=TPacketClass(FindClass(reqClassName)).Create;
try
req.DeSerialize(node);
SendResponse(req.Invoke.Serialize);
finally
req.Free;
end;
end;
except
end
finally
CoUninitialize;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ss.Active:=true;
end;
{ TPacket }
procedure TPacket.DeSerialize(ANode: OleVariant);
procedure SetObjectProperty(AObject:TObject;APropName:string;APropValue:Variant);
var
Props: PPropList;
TypeData: PTypeData;
i:integer;
begin
TypeData := GetTypeData(AObject.ClassInfo);
if (TypeData = nil) or (TypeData^.PropCount = 0) then Exit;
GetMem(Props, TypeData^.PropCount * sizeof(Pointer));
try
GetPropInfos(AObject.ClassInfo, Props);
for i := 0 to TypeData^.PropCount-1 do
if AnsiUpperCase(PPropInfo(Props^[I]).Name)=AnsiUpperCase(APropName) then
case Props^[I]^.PropType^.Kind of
tkChar, tkString, tkLString, tkWChar, tkWString: // ?????????? ??????
begin
SetStrProp(AObject, Props^[I], String(APropValue));
end;
tkInteger,tkEnumeration: // ????? ?????
begin
SetOrdProp(AObject, Props^[I], APropValue);
end;
tkFloat:
// ????? ? ????????? ??????
begin
SetFloatProp(AObject, Props^[I], APropValue);
end;
end;
finally
Freemem(Props);
end;
end;
var
i:integer;
node:OleVariant;
begin
node:=ANode.selectSingleNode("DATA");
for i:=0 to node.attributes.length-1 do
SetObjectProperty(self,node.attributes.item(i).name,node.attributes.item(i).value);
end;
function TPacket.Serialize: string;
function GetObjectPropertis(AObject:TObject):string;
var
Props: PPropList;
TypeData: PTypeData;
i:integer;
sl:TStringList;
begin
sl:=TStringList.Create;
TypeData := GetTypeData(AObject.ClassInfo);
if (TypeData = nil) or (TypeData^.PropCount = 0) then Exit;
GetMem(Props, TypeData^.PropCount * sizeof(Pointer));
try
GetPropInfos(AObject.ClassInfo, Props);
for i := 0 to TypeData^.PropCount-1 do
case Props^[I]^.PropType^.Kind of
tkChar, tkString, tkLString, tkWChar, tkWString: // ?????????? ??????
begin
sl.Add(Format("%s="%s"",[AnsiUpperCase(PPropInfo(Props^[I]).Name),GetStrProp(AObject, Props^[I])]));
end;
tkInteger,tkEnumeration: // ????? ?????
begin
sl.Add(Format("%s="%d"",[AnsiUpperCase(PPropInfo(Props^[I]).Name),GetOrdProp(AObject, Props^[I])]));
end;
tkFloat: // ????? ? ????????? ??????
begin
sl.Add(Format("%s="%f"",[AnsiUpperCase(PPropInfo(Props^[I]).Name),GetFloatProp(AObject, Props^[I])]));
end;
end;
sl.Insert(0,"<DATA");
sl.Add("/>");
Result:=sl.Text;
finally
Freemem(Props);
sl.Free;
end;
end;
begin
Result:=Format("<PACKET TYPE="%s">%s</PACKET>",[ClassName,GetObjectPropertis(self)])+#13#10;
end;
{ TSumRequest }
function TSumRequest.Invoke: TPacket;
begin
Result:=TSumResponse.Create;
TSumResponse(Result).Sum:=A+B;
end;
{ TSumResponse }
function TSumResponse.Invoke: TPacket;
begin
//
end;
initialization
Classes.RegisterClass(TSumRequest);
Classes.RegisterClass(TSumResponse);
end.
← →
Polevi (2003-11-13 16:15) [15]запускаем программу
подключаемся телнетом и отправляем серверу запрос
<PACKET TYPE="TSumRequest">
<DATA A="10" B="5"/>
</PACKET>
и радуемся :-)
← →
Fredericco (2003-11-13 18:27) [16]2 VID © (12.11.03 22:00) [6]
Во превых, та сам прикинь, при каждой передаче файла у тебя будет уходить мин. 2 секунды только на коннект. Сколько ты будешь копировать 10 файлов по 3 байта? Правда очень не эффективно :-). Но все же такой вариант редко делают, но соединение вторичное устанавливают, сразу с первичным. Повторюсь редко так делают, тебе ИМХО так не надо.
← →
VID (2003-11-13 22:55) [17]To Fredericco: Я как то не подумал что вторичное соединение можно установить сразу после первичного и держаеть его на протяжении всего первичного соединения.. если так то задержки на коннект практически ничего не значат... конечно остаётся куча доп. проблем связаных с этим самым вторичным соединением...
ну да.. тут надо подумать, пока что этот вопрос для меня остаётся открытым
To Polevi: Можно узнать твой ICQ-номер, на случай вопросов ? В Аське скорость познаний быстрее :)
← →
Polevi (2003-11-14 14:03) [18]>VID © (13.11.03 22:55) [17]
sergсобакаfinco.spb.ru
← →
VaS (2003-11-16 09:24) [19]Poveli: Изобретаем свой SOAP? :)
← →
Polevi (2003-11-16 17:58) [20]>VaS (16.11.03 09:24) [19]
свой всегда лучше :-)
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.011 c