Форум по 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). Всё ли будет правильно обрабатываться, если сообщения одновременно могут прийти от разных клиентов ?
__________________
Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей
Ответить с цитированием
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

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