Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Интернет и сети
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 20.02.2011, 16:47
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Восклицание Вопрос по поводу приема объединеных структур и их разделение

Здравствуйте, возник такой вопрос:
Я начал писать клиент-серверное приложение и решил передавать данные с помощью разных структур. В интернете читал, искал примеры, но подходящие были связаны лишь с работой со строками.
Но у меня же всё иначе.
Для начала первый вопрос:
1.1 например имеем заранее известную структуру, допустим такую:
Код:
TMyStructure = packed record
A:Byte;
B:Single;
C:Integer;
end;
Когда одновременно клиенту приходит несколько одинаковых блоков одной и той же структуры, то их мне получается необходимо разделить на различные и каждую обработать соответственно. НО !
1.2 Учесть, что если вдруг сразу не придет целиком одна структура.
(т.е. её необходимо дочитать до полной структуры).
2) всё также, как и в первом вопросе, но только мы допустим имеем несколько различных структур, как их правильно принять и разделить ?
______
Исходя из того, что я читал, мне получается нужно ввести какую-то уникальную сигнатуру каждого пакета(или точнее структуры), что если структура допустим первая, то у нее:
Код:
TMyStructure = packed record
sign:Byte; // Сигнатура
A:Byte;
B:Single;
C:Integer;
end;
если вторая, то:
Код:
TMyStructure2 = packed record
sign:Byte; // Сигнатура
A:String[20];
B:Integer;
C:array[1..10] of Single;
end;
И мы соответственно при передаче структур этих заполняем Sign для первой = 1, для второй структуры Sign = 2;
В общем нужен какой-то разделить или что-то подобное сигнатуры.
И ещё вопрос насчет пункта 1.2: если структура небольшого размера, то вообще возможно ли такое, что она прийдет не вся целиком ? скорее всего возможно, поэтому я и задал этот вопрос.
Помогите пожалуйста разобраться.
___
Ах да, ещё у меня такая мысль была, что если передавать массив байт, а в конце например сигнатуру FF FF FF, но будет довольно сложно каждый тип данных привести из байт к своему, например тотже Single из байт в Single и наоборот, также с каждым типом.
Хотя эта идея мне кажется интересной. Помогите может какие идеи насчет этого есть. Т.к. Этот способ кажется попроще, но и возникает проблема с преобразованием байт в соответствующие типы. С нетерпением жду ответов.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 20.02.2011 в 16:51.
Ответить с цитированием
  #2  
Старый 20.02.2011, 17:25
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

один из вариантов мультиплексирования:
-перед каждой структурой сервер передает либо ее "тип", либо ее размер
-клиент сперва считывает "тип" (и по типу определяет размер структуры) или размер структуры
-затем ожидает во входном буфере данных этого или большего объема
-когда данные есть, считывает объем, равный размеру структуры
-остальные данные будут относиться к следующей структуре - опять "тип" или размер+сама структура

однако сокетные данные бьются, если их размер больше 8К = 8192 байта, имхо
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #3  
Старый 20.02.2011, 18:09
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Сообщение

Это конечно понятно, принцип по какому нужно работать.
Но хотелось бы примера, пожалуйста.
И вообще мне больше нравится вариант последний, который я описывал, как массив байт, возможно ли и как подобное реализовать ?
Например мне нужны следующие типы данных, которые я буду передавать в структурах:
Single, Integer, Char; самые основные пусть будут эти..как это передать и перевести обратно. например разделителем будет определенный код в конце по которому и будут разделяться пакеты..
Тогда тут будет выигрыш в том, что я могу передавать лишь определенные байты и все будет гораздо проще разделяться и т.п., ну это на мой взгляд.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #4  
Старый 21.02.2011, 12:03
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

один из вариантов мультиплексинга:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ScktComp;

type
  PRec1 = ^TRec1;
  TRec1 = record
    ID: Word;
    Data: String[32];
  end;

  PRec2 = ^TRec2;
  TRec2 = record
    ID: Word;
    Parent: Word;
    Data: String[32];
  end;

  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    CheckBox1: TCheckBox;
    Memo1: TMemo;
    ClientSocket1: TClientSocket;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure CheckBox1Click(Sender: TObject);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
    FPipeRead: THandle;
    FPipeWrite: THandle;
    FDataLen: DWORD;
    procedure Multiplex;
    procedure Notify(data: PChar; len: DWORD);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

const
  PipeSize: Cardinal = 1024*1024;

implementation

{$R *.dfm}

procedure TForm1.Multiplex;
var
  len: DWORD;
  data: PChar;
  dummy: Cardinal;
begin
  while True do
  begin
    len:=GetFileSize(FPipeRead, nil);
    if len=0 then Break;

    if FDataLen=0 then
    begin
      if len<SizeOf(DWORD) then Break;
      ReadFile(FPipeRead, FDataLen, SizeOf(DWORD), dummy, nil);
    end else
    begin
      if len<FDataLen then Break;
      GetMem(data, FDataLen);
      ReadFile(FPipeRead, data^, FDataLen, dummy, nil);
      Notify(data, FDataLen);
      FreeMem(data);
      FDataLen:=0;
    end;
  end;
end;

procedure TForm1.Notify(data: PChar; len: DWORD);
begin
  Memo1.Lines.Add('--');
  case len of
    SizeOf(TRec1): begin
      Memo1.Lines.Add('ID='+IntToStr(PRec1(data)^.ID));
      Memo1.Lines.Add('Data='+PRec1(data)^.Data);
    end;
    SizeOf(TRec2): begin
      Memo1.Lines.Add('ID='+IntToStr(PRec2(data)^.ID));
      Memo1.Lines.Add('Parent='+IntToStr(PRec2(data)^.Parent));
      Memo1.Lines.Add('Data='+PRec2(data)^.Data);
    end;
  end;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  ServerSocket1.Active:=CheckBox1.Checked;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  len: DWORD;
  data: PChar;
  dummy: Cardinal;
begin
  len:=Socket.ReceiveLength;
  GetMem(data, len);
  len:=Socket.ReceiveBuf(data^, len);
  WriteFile(FPipeWrite, data^, len, dummy, nil);
  FreeMem(data);
  Multiplex;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CreatePipe(FPipeRead, FPipeWrite, nil, PipeSize);
  FDataLen:=0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  CloseHandle(FPipeWrite);
  CloseHandle(FPipeRead);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  rec1: TRec1;
  buf: DWORD;
begin
  ClientSocket1.Open;
  rec1.ID:=$1;
  rec1.Data:='avatar';
  buf:=SizeOf(rec1);
  ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
  ClientSocket1.Socket.SendBuf(rec1, SizeOf(rec1));
  ClientSocket1.Close;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  rec2: TRec2;
  buf: DWORD;
begin
  ClientSocket1.Open;
  rec2.ID:=$2;
  rec2.Parent:=$1;
  rec2.Data:='the stol';
  buf:=SizeOf(rec2);
  ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
  ClientSocket1.Socket.SendBuf(rec2, SizeOf(rec2));
  ClientSocket1.Close;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  rec1: TRec1;
  rec2: TRec2;
  buf: DWORD;
  i: Integer;
begin
  ClientSocket1.Open;
  for i:=1 to 10 do
  begin
    rec1.ID:=i;
    rec1.Data:='avatar';
    buf:=SizeOf(rec1);
    ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
    ClientSocket1.Socket.SendBuf(rec1, SizeOf(rec1));

    rec2.ID:=i*100;
    rec2.Parent:=i;
    rec2.Data:='the stol';
    buf:=SizeOf(rec2);
    ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
    ClientSocket1.Socket.SendBuf(rec2, SizeOf(rec2));
  end;

  ClientSocket1.Close;
end;

end.
http://data.cod.ru/90155

TCheckBox вкл/выкл сервер
Open1 посылает 1 тип рекорда
Open2 посылает 2 тип рекорда
OpenMany посылает 10 раз [1 тип, 2 тип]
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #5  
Старый 21.02.2011, 17:07
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Хорошо Спасибо огромнейшее...

Большое спасибо, замечательный пример.
Буду теперь делать все по такому принципу, очень понравился пример, просто супер, огромное спасибо ещё раз.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #6  
Старый 21.02.2011, 18:26
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Вопрос Вопрос:

Сейчас начал писать обработки и возник такой вопрос...
а могу ли я сделать так:
Код:
procedure ServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  <...>
begin
 < ...>
  Multiplex(Socket);
end;


 procedure Multiplex(mSock: TCustomWinSocket);
var
  <...>
begin
 <...>
      Notify(data, FDataLen,mSock);
 <...>
end;

procedure Notify(data: PChar; len: DWORD;mFrom: TCustomWinSocket);
begin
 <...>
 {Просто здесь мне нужен сокет, например чтобы отправить по заданному адресу обратно сообщение какое-то в зависимости от того, что пришло.}
end;

Будет ли такая конструкция правильно работать ? Если я добавил в аргумент каждой функции ещё один параметр, не будет ли путанницы ?
просто подобный способ нужен на сервере(TServerSocket). Всё ли будет правильно обрабатываться, если сообщения одновременно могут прийти от разных клиентов ?
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #7  
Старый 21.02.2011, 19:47
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
По умолчанию

Заметил, что происходит ошибка и данные отправляются совсем другие, если серверу приходит что-то от одного клиента и другого почти одновременно(различные структуры)...
После ошибки(замечено, что пакеты другие) сервер уже не распознает структуры совсем..
__________
может стоит описать суть задачи, чтобы вы дали самый оптимальный вариант её реализации..
Имеется сервер. Есть клиенты.. каждый клиент шлет какие-то данные серверу, иногда сервер должен рассылать какие-то данные, пришедшие от одного клиента, а иногда просто отвечать на запросы конкретного клиента, подскажите пожалуйста как подобное лучше всего реализовать.
________
Как можно исправить такую ситуацию ? что нужно сделать ? если произойдет ошибка и приложение(не важно сервер это или клиент) распознает пакет как пакет определенной структуры(но на самом деле он неверный, там будет совсем не то, что должно было прийти), потом вообще просто перестают распознаваться пакеты как данные определенной структуры... они приходят, событие OnRead происходит, а вот уже не распознаются. что делать ?
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей

Последний раз редактировалось Oleg, 22.02.2011 в 13:55.
Ответить с цитированием
  #8  
Старый 23.02.2011, 01:20
Аватар для Oleg
Oleg Oleg вне форума
Активный
 
Регистрация: 29.11.2007
Адрес: Оренбургская обл., Россия
Сообщения: 261
Репутация: 15
Печаль Помогите пожалуйста

Люди, подскажите пожалуйста как мне быть ?
Как правильно реализовать взаимодействие с сервером нескольких клиентов ?
У меня и клиенты и сервер в неблокирующем режиме. Может нужно как-то перевести сервер на блокирующий ? подскажите как правильно реализовать это. Очень долго искал в интернете везде, не нашел подходящих примеров, тем более для блокирующего сокета.
Мне понравилась реализация, предложенная NumLock, но вот только если одновременно прислать пакеты с разных клиентов, то происходит ошибка, т.к. пакеты начинают идти не в том порядке(например пришел кусок от первого и тут же от второго, другой) => данные искажаются и получается вообще каша. После этого вообще перестает работать такая конструкция распознавания пакетов. Как возобновить правильность ? Тут наверное нужен блокирующий сервер.
Подскажите пожалуйста, уже пару дней без успеха бьюсь и ищу, а толку нет.
Может кто подскажет пример по принципу сигнатур пакетов, теорию которого я описывал в самом начале темы ?! Просто сам не могу подобное сделать, поэтому и прошу помощь знающих и разбирающихся в этой области людей, пожалуйста, помогите разобраться, буду очень признателен вам за это.
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
  #9  
Старый 24.02.2011, 13:41
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ScktComp, StdCtrls;

type
  PRec1 = ^TRec1;
  TRec1 = record
    ID: Word;
    Data: String[32];
  end;

  PRec2 = ^TRec2;
  TRec2 = record
    ID: Word;
    Parent: Word;
    Data: String[32];
  end;

  TMyServerClientThread = class(TServerClientThread)
  private
    FPipeRead: THandle;
    FPipeWrite: THandle;
    FDataLen: DWORD;
    FStr: String;
    procedure Multiplex;
    procedure Notify(Buffer: PChar; Len: DWORD);
    procedure UpdateThread;
  protected
    procedure ClientExecute; override;
  public
    constructor Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket);
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    CheckBox1: TCheckBox;
    Memo1: TMemo;
    ClientSocket1: TClientSocket;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Memo2: TMemo;
    CheckBox2: TCheckBox;
    ClientSocket2: TClientSocket;
    procedure CheckBox1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure ServerSocket1GetThread(Sender: TObject;
      ClientSocket: TServerClientWinSocket;
      var SocketThread: TServerClientThread);
    procedure CheckBox2Click(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocket2Read(Sender: TObject; Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

const
  PipeSize: Cardinal = 1024*1024;

implementation

{$R *.dfm}

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  ServerSocket1.Active:=CheckBox1.Checked;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  ClientSocket1.Active:=CheckBox2.Checked;
  ClientSocket2.Active:=CheckBox2.Checked;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  rec1: TRec1;
  buf: DWORD;
begin
  rec1.ID:=$1;
  rec1.Data:='avatar';
  buf:=SizeOf(rec1);
  ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
  ClientSocket1.Socket.SendBuf(rec1, SizeOf(rec1));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  rec2: TRec2;
  buf: DWORD;
begin
  rec2.ID:=$2;
  rec2.Parent:=$1;
  rec2.Data:='the stol';
  buf:=SizeOf(rec2);
  ClientSocket1.Socket.SendBuf(buf, SizeOf(DWORD));
  ClientSocket1.Socket.SendBuf(rec2, SizeOf(rec2));
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  rec1: TRec1;
  rec2: TRec2;
  buf: DWORD;
  i: Integer;
begin
  for i:=1 to 10 do
  begin
    rec1.ID:=i;
    rec1.Data:='many avatar';
    buf:=SizeOf(rec1);
    ClientSocket2.Socket.SendBuf(buf, SizeOf(DWORD));
    ClientSocket2.Socket.SendBuf(rec1, SizeOf(rec1));

    rec2.ID:=i*100;
    rec2.Parent:=i;
    rec2.Data:='many the stol';
    buf:=SizeOf(rec2);
    ClientSocket2.Socket.SendBuf(buf, SizeOf(DWORD));
    ClientSocket2.Socket.SendBuf(rec2, SizeOf(rec2));
  end;
end;

procedure TForm1.ServerSocket1GetThread(Sender: TObject;
  ClientSocket: TServerClientWinSocket;
  var SocketThread: TServerClientThread);
begin
  SocketThread:=TMyServerClientThread.Create(False, ClientSocket);
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Memo2.Lines.Add(Socket.ReceiveText);
end;

procedure TForm1.ClientSocket2Read(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Memo2.Lines.Add(Socket.ReceiveText);
end;

{ TMyServerClientThread }

constructor TMyServerClientThread.Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket);
begin
  CreatePipe(FPipeRead, FPipeWrite, nil, PipeSize);
  FDataLen:=0;
  FStr:='Create';
  Synchronize(UpdateThread);
  inherited Create(CreateSuspended, ASocket);
end;

destructor TMyServerClientThread.Destroy;
begin
  inherited Destroy;
  CloseHandle(FPipeWrite);
  CloseHandle(FPipeRead);
end;

procedure TMyServerClientThread.ClientExecute;
var
  Stream: TWinSocketStream;
  Buffer: array [0..$ff] of Char;
  Len: Integer;
  dummy: Cardinal;
begin
  while not Terminated and ClientSocket.Connected do
  begin
    Stream:=TWinSocketStream.Create(ClientSocket, 60000);
    try
      if Stream.WaitForData(60000) then
      begin
        Len:=Stream.Read(Buffer, Length(Buffer));
        if Len=0 then ClientSocket.Close;
        WriteFile(FPipeWrite, Buffer[0], Len, dummy, nil);
        Multiplex;
      end else ClientSocket.Close;
    finally
      Stream.Free;
    end;
  end;
end;

procedure TMyServerClientThread.Multiplex;
var
  len: DWORD;
  data: PChar;
  dummy: Cardinal;
begin
  while True do
  begin
    len:=GetFileSize(FPipeRead, nil);
    if len=0 then Break;
    if FDataLen=0 then
    begin
      if len<SizeOf(DWORD) then Break;
      ReadFile(FPipeRead, FDataLen, SizeOf(DWORD), dummy, nil);
    end else
    begin
      if len<FDataLen then Break;
      GetMem(data, FDataLen);
      ReadFile(FPipeRead, data^, FDataLen, dummy, nil);
      Notify(data, FDataLen);
      FreeMem(data);
      FDataLen:=0;
    end;
  end;
end;

procedure TMyServerClientThread.Notify(Buffer: PChar; Len: DWORD);
begin
  FStr:='--'#13#10;
  case len of
    SizeOf(TRec1): begin
      FStr:=FStr+'ID='+IntToStr(PRec1(Buffer)^.ID)+#13#10;
      FStr:=FStr+'Data='+PRec1(Buffer)^.Data+#13#10;
    end;
    SizeOf(TRec2): begin
      FStr:=FStr+'ID='+IntToStr(PRec2(Buffer)^.ID)+#13#10;
      FStr:=FStr+'Parent='+IntToStr(PRec2(Buffer)^.Parent)+#13#10;
      FStr:=FStr+'Data='+PRec2(Buffer)^.Data+#13#10;
    end;
  end;
  Synchronize(UpdateThread);
  ClientSocket.SendText(FStr);
end;

procedure TMyServerClientThread.UpdateThread;
begin
  Form1.Memo1.Lines.Add(FStr);
end;

end.

ServerSocket
ClientSocket
Open1 посылает 1 тип рекорда
Open2 посылает 2 тип рекорда
OpenMany посылает 10 раз [1 тип, 2 тип]

http://data.cod.ru/90607
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 00:00.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter