![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
||||
|
||||
|
Здравствуйте, возник такой вопрос:
Я начал писать клиент-серверное приложение и решил передавать данные с помощью разных структур. В интернете читал, искал примеры, но подходящие были связаны лишь с работой со строками. Но у меня же всё иначе. Для начала первый вопрос: 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; В общем нужен какой-то разделить или что-то подобное сигнатуры. И ещё вопрос насчет пункта 1.2: если структура небольшого размера, то вообще возможно ли такое, что она прийдет не вся целиком ? скорее всего возможно, поэтому я и задал этот вопрос. Помогите пожалуйста разобраться. ___ Ах да, ещё у меня такая мысль была, что если передавать массив байт, а в конце например сигнатуру FF FF FF, но будет довольно сложно каждый тип данных привести из байт к своему, например тотже Single из байт в Single и наоборот, также с каждым типом. Хотя эта идея мне кажется интересной. Помогите может какие идеи насчет этого есть. Т.к. Этот способ кажется попроще, но и возникает проблема с преобразованием байт в соответствующие типы. С нетерпением жду ответов. Последний раз редактировалось Oleg, 20.02.2011 в 16:51. |
|
#2
|
||||
|
||||
|
один из вариантов мультиплексирования:
-перед каждой структурой сервер передает либо ее "тип", либо ее размер -клиент сперва считывает "тип" (и по типу определяет размер структуры) или размер структуры -затем ожидает во входном буфере данных этого или большего объема -когда данные есть, считывает объем, равный размеру структуры -остальные данные будут относиться к следующей структуре - опять "тип" или размер+сама структура однако сокетные данные бьются, если их размер больше 8К = 8192 байта, имхо |
|
#3
|
||||
|
||||
|
Это конечно понятно, принцип по какому нужно работать.
Но хотелось бы примера, пожалуйста. И вообще мне больше нравится вариант последний, который я описывал, как массив байт, возможно ли и как подобное реализовать ? Например мне нужны следующие типы данных, которые я буду передавать в структурах: Single, Integer, Char; самые основные пусть будут эти..как это передать и перевести обратно. например разделителем будет определенный код в конце по которому и будут разделяться пакеты.. Тогда тут будет выигрыш в том, что я могу передавать лишь определенные байты и все будет гораздо проще разделяться и т.п., ну это на мой взгляд. |
|
#4
|
||||
|
||||
|
один из вариантов мультиплексинга:
Код:
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.
TCheckBox вкл/выкл сервер Open1 посылает 1 тип рекорда Open2 посылает 2 тип рекорда OpenMany посылает 10 раз [1 тип, 2 тип] |
|
#5
|
||||
|
||||
|
Большое спасибо, замечательный пример.
Буду теперь делать все по такому принципу, очень понравился пример, просто супер, огромное спасибо ещё раз. |
|
#6
|
||||
|
||||
|
Сейчас начал писать обработки и возник такой вопрос...
а могу ли я сделать так: Код:
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). Всё ли будет правильно обрабатываться, если сообщения одновременно могут прийти от разных клиентов ? |