|
|
Регистрация | << Правила форума >> | 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). Всё ли будет правильно обрабатываться, если сообщения одновременно могут прийти от разных клиентов ? Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей |
#7
|
||||
|
||||
Заметил, что происходит ошибка и данные отправляются совсем другие, если серверу приходит что-то от одного клиента и другого почти одновременно(различные структуры)...
После ошибки(замечено, что пакеты другие) сервер уже не распознает структуры совсем.. __________ может стоит описать суть задачи, чтобы вы дали самый оптимальный вариант её реализации.. Имеется сервер. Есть клиенты.. каждый клиент шлет какие-то данные серверу, иногда сервер должен рассылать какие-то данные, пришедшие от одного клиента, а иногда просто отвечать на запросы конкретного клиента, подскажите пожалуйста как подобное лучше всего реализовать. ________ Как можно исправить такую ситуацию ? что нужно сделать ? если произойдет ошибка и приложение(не важно сервер это или клиент) распознает пакет как пакет определенной структуры(но на самом деле он неверный, там будет совсем не то, что должно было прийти), потом вообще просто перестают распознаваться пакеты как данные определенной структуры... они приходят, событие OnRead происходит, а вот уже не распознаются. что делать ? Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей Последний раз редактировалось Oleg, 22.02.2011 в 13:55. |
#8
|
||||
|
||||
Помогите пожалуйста
Люди, подскажите пожалуйста как мне быть ?
Как правильно реализовать взаимодействие с сервером нескольких клиентов ? У меня и клиенты и сервер в неблокирующем режиме. Может нужно как-то перевести сервер на блокирующий ? подскажите как правильно реализовать это. Очень долго искал в интернете везде, не нашел подходящих примеров, тем более для блокирующего сокета. Мне понравилась реализация, предложенная NumLock, но вот только если одновременно прислать пакеты с разных клиентов, то происходит ошибка, т.к. пакеты начинают идти не в том порядке(например пришел кусок от первого и тут же от второго, другой) => данные искажаются и получается вообще каша. После этого вообще перестает работать такая конструкция распознавания пакетов. Как возобновить правильность ? Тут наверное нужен блокирующий сервер. Подскажите пожалуйста, уже пару дней без успеха бьюсь и ищу, а толку нет. Может кто подскажет пример по принципу сигнатур пакетов, теорию которого я описывал в самом начале темы ?! Просто сам не могу подобное сделать, поэтому и прошу помощь знающих и разбирающихся в этой области людей, пожалуйста, помогите разобраться, буду очень признателен вам за это. Если Вы находите ошибки, исправить которые дело долгое и нудное, ничего не делайте - просто внесите их в список особенностей |
#9
|
||||
|
||||
Код:
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 Пишу программы за еду. __________________ |