Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Отправка данных методом SendBuf, Пакеты разной длины и структуры 
V
    Опции темы
K0T9I
Дата 15.6.2010, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 20.11.2009

Репутация: нет
Всего: 2



всем привет, есть структура пакета:
Код

TPacketHeader = packed record
  id:word;
  len:word;
end;

TPacketData = Pointer;

TPacket = packed record
  header:TPacketHeader;
  data:TPacketData;
end;


заполнение и отправка пакета:
Код

procedure TForm1.Button1Click(Sender: TObject);
var pck:TPacket;
begin
  ClientSocket1.Active:=true;
  pck.header.id:=1;
  pck.header.len:=4;
  GetMem(pck.data,pck.header.len);
  dword(pointer(pck.data)^):=65525;
  ClientSocket1.Socket.SendBuf(pck,SizeOf(TPacketHeader)+SizeOf(TPacketData));
  ClientSocket1.Active:=false;
end;


Я сделал pck.data типа pointer, так как структура и длина данных в различных пакетах могут быть разными.
Потом до меня дошло, что отправляется только указатель pck.data, а не сами данные.

Как отправить данные функцией SendBuf, учитывая то, что они могут быть разной длины и структуры?
PM MAIL   Вверх
kami
Дата 15.6.2010, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 6
Всего: 72



Как вариант пример передачи данных по TCP.
Если не использовать этот пример, то - почитайте тему в ссылке, некоторые вопросы прояснятся.

Цитата(K0T9I @  15.6.2010,  11:03 Найти цитируемый пост)
учитывая то, что они могут быть разной длины и структуры?

И могут разбиваться и склеиваться друг с другом. И не полностью передаваться.
Общие принципы передачи:
При начале передачи устанавливаем Pos на 0.
В каждом событии OnWrite пытаемся передать все данные, начиная от Pos. Увеличиваем Pos на количество реально переданных байт.
Когда Pos=длине данных, "убиваем" данные и начинаем пытаться передать следующие.
P.S. Заголовок и сами данные передаем "отдельно", они все равно склеятся по дороге.

Общие принципы приема (событие OnRead)
Забираем полностью приемный буфер сокета.
Пока буфер не пуст:
 - если заголовок не принят, "выбираем" из приемного буфера данные в заголовок, удаляем из приемного буфера обработанные данные.
 - если буфер не закончился, то
    - смотрим длину данных из заголовка
    - создаем буфер для данных.
    - выбираем из приемного буфера в буфер данных максимально возможное количество данных (Min(длина_приемного_буфера, остаток_до_полного приема_данных) ).
   - удаляем из приемного буфера обработанные данные.
  - если данные приняты полностью, то отправляем заголовок и данные "куда надо", после чего считаем, что заголовок и данные не приняты.
и на новый виток цикла.

Добавлено через 3 минуты и 30 секунд
Цитата(K0T9I @  15.6.2010,  11:03 Найти цитируемый пост)
 ClientSocket1.Active:=false;

В каком режиме работают сокеты?
ctNonBlocking или ctThreadBlocking?
PM MAIL WWW   Вверх
K0T9I
Дата 15.6.2010, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 20.11.2009

Репутация: нет
Всего: 2



Цитата

И могут разбиваться и склеиваться друг с другом.

это я знаю, делаю так:
Код

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  dataLen,fullLen,newLen:word;
  len:integer;
  i:integer;
  buf:Pointer;

function getPacketLen(stream:TMemoryStream):word;
var len:word;
oldPos:dword;
begin
  result:=0;
  if stream.Size>=SizeOf(TPacketHeader) then
  begin
    oldPos:=stream.Position;
    stream.Position:=2;
    stream.ReadBuffer(len,2);
    result:=len;
    stream.Position:=oldPos;
  end;
end;

begin
  for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do 
  begin
    if ServerSocket1.Socket.Connections[i].SocketHandle=Socket.SocketHandle then
    begin
      TMemoryStream(Socket.Data).Position:=TMemoryStream(Socket.Data).Size;
      len:=Socket.ReceiveLength;
      GetMem(buf,len);
      Socket.ReceiveBuf(buf^,len);
      TMemoryStream(Socket.Data).WriteBuffer(buf^,len);
      FreeMem(buf);

      dataLen:=getPacketLen(TMemoryStream(Socket.Data));
      fullLen:=dataLen+SizeOf(TPacketHeader);

      while TMemoryStream(Socket.Data).Size>=fullLen do
      begin
        TMemoryStream(Socket.Data).Position:=0;
        GetMem(buf,fullLen);
        TMemoryStream(Socket.Data).ReadBuffer(buf^,fullLen);
        ProcessPacket(buf);
        FreeMem(buf);

        newLen:=TMemoryStream(Socket.Data).Size-fullLen;
        if newLen=0 then break;

        GetMem(buf,newLen);
        TMemoryStream(Socket.Data).Position:=fullLen;
        TMemoryStream(Socket.Data).ReadBuffer(buf^,newLen);
        TMemoryStream(Socket.Data).SetSize(0);
        TMemoryStream(Socket.Data).Position:=0;
        TMemoryStream(Socket.Data).WriteBuffer(buf^,newLen);
        FreeMem(buf);

        dataLen:=getPacketLen(TMemoryStream(Socket.Data));
        fullLen:=dataLen+SizeOf(TPacketHeader);
      end; // while TMemoryStream(Socket.Data).Size>=fullLen
      break;
    end; // if ServerSocket1.Socket.Connections[i].SocketHandle=Socket.SocketHandle 
  end; // for i:=0 to ServerSocket1.Socket.ActiveConnections-1
end;

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var Stream:TMemoryStream;
begin
  Stream:=TMemoryStream.Create;
  Socket.Data:=Stream;
end;

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var i:integer;
begin
  TMemoryStream(Socket.Data).Free;
end;


Цитата

И не полностью передаваться.

про это слышал, но упустил из виду, спасибо что напомнилиsmile

Цитата

В каком режиме работают сокеты?
ctNonBlocking или ctThreadBlocking?

stNonBlocking
ctBlocking

Это сообщение отредактировал(а) K0T9I - 15.6.2010, 13:50
PM MAIL   Вверх
kami
Дата 15.6.2010, 17:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 6
Всего: 72



Цитата(K0T9I @  15.6.2010,  13:39 Найти цитируемый пост)
 for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do   begin    if ServerSocket1.Socket.Connections[i].SocketHandle=Socket.SocketHandle then

Зачем? Лишние телодвижения.
Все равно в теле цикла работаете с параметром Socket, переданным в обработчик события. А он в любом случае равен одному из Connections[i].
остальное вроде нормально (хотя, честно говоря - смотрел бегло, сегодня некогда).

Ну, и возвращаясь к первоначальному вопросу - 

Цитата(K0T9I @  15.6.2010,  11:03 Найти цитируемый пост)
Как отправить данные функцией SendBuf, учитывая то, что они могут быть разной длины и структуры?

отдельно передаем заголовок, отдельно - данные. Все равно по дороге с ними непонятно что произойдет smile
Как-то так:
Код

ClientSocket1.Socket.SendBuf(pck.Header,SizeOf(TPacketHeader));
ClientSocket1.Socket.SendBuf(pck.Data^,psk.Header.Len); // так как SizeOf (TPacketData)=8 - размер указателя.

PM MAIL WWW   Вверх
K0T9I
Дата 15.6.2010, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 20.11.2009

Репутация: нет
Всего: 2



спасибо за ссылку на ваш компонент, нигде не мог найти нормальный пример использования sendbuf/sendstream, везде текстом посылают.

по своему вопросу решил сделать так, хотя скорей всего это костыль:

Код

procedure ProcessPacket(buf:pointer);
var pck:TPacket;
    p:pointer;
begin
  pck.header.id:=word(buf^);
  pck.header.len:=word(pointer(dword(buf)+SizeOf(word))^);
  if (pck.header.len>0) then
  begin
    GetMem(pck.data,pck.header.len);
    p:=pointer(dword(buf)+SizeOf(TPacketHeader));
    CopyMemory(pck.data,p,pck.header.len);
  end;

  case pck.header.id of

  end;
  
  if (pck.header.len>0) then FreeMem(pck.data);
end;

...................

procedure TForm1.Button1Click(Sender: TObject);
var pck:TPacket;
    exStream:TMemoryStream;
    buf:pointer;
begin
  ClientSocket1.Active:=true;

  pck.header.id:=1; // формирование пакета
  pck.header.len:=4;
  GetMem(pck.data,pck.header.len);
  dword(pck.data^):=GetCurrentProcessID;
  
  exStream:=TMemoryStream.Create; // запись данных пакета в буфер
  exStream.WriteBuffer(pck.header,SizeOf(TPacketHeader));
  exStream.Position:=SizeOf(pck.header);
  exStream.WriteBuffer(pck.data^,pck.header.len);
  GetMem(buf,exStream.size);
  exStream.Position:=0;
  exStream.ReadBuffer(buf^,exStream.size);

  ClientSocket1.Socket.SendBuf(buf^,exStream.size);  //посылка

  FreeMem(buf);
  exStream.Free;
  FreeMem(pck.data);

  ClientSocket1.Active:=false;
end;


upd: сделал так, спасибо kami
Цитата

Как-то так:Код

ClientSocket1.Socket.SendBuf(pck.Header,SizeOf(TPacketHeader));
ClientSocket1.Socket.SendBuf(pck.Data^,psk.Header.Len); // так как SizeOf (TPacketData)=8 - размер указателя.


Это сообщение отредактировал(а) K0T9I - 16.6.2010, 09:37
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.0860 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.