Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.01.01;
Скачать: CL | DM;

Вниз

Сокеты "склеивают" сообщения!   Найти похожие ветки 

 
Galiaf   (2005-09-20 20:31) [0]

Драсти. Проблема такая: если очень быстро послать сокетом текст "привет" то придёт он в таком виде "приветпривет" :(.
Не катит!
Помогите с проблемой разобраться, как отправлять что бы не склеивало, потому что отправлять придётся много и быстро, это будет использоваться в сетевой игре и отсылать буду очень важные данные.


 
KLAUS ©   (2005-09-20 20:47) [1]

А ты как вообще отправляешь?

procedure TForm1.Button1Click(Sender: TObject);
 begin

   ClientSocket1.Socket.SendText(Edit1.Text);
      Edit13.Text := "";
   ActiveControl := Edit13;
end;


 
Galiaf   (2005-09-20 21:22) [2]

Отправлял я по нажатию на Enter но без строки "ActiveControl := Edit13;", а что она делает?


 
kami ©   (2005-09-20 21:29) [3]


> что бы не склеивало

1.Посылать перед каждым текстом его длину [ другую служебную информацию ]
2.Сохранять всё принятое в конец MemoryStream
3.Просматривать с начала MemoryStream после каждого приема, выбирая пришедшие полностью сообщения и, соответственно, удаляя их из потока.

Это защитит не только от склеивания, но и от разбиения по пакетам.


 
XProger ©   (2005-09-20 22:01) [4]

http://xproger.mirgames.ru/files/lib/l_net.rar

Библиотека готового сетевого протокола основанного на UDP. Имеется реализация гарантированной доставки пакетов, а также широковещательные рассылки. Прилагается пример чата. Прирост к исполняемому файлу составляет 5.5 кб!


 
Galiaf   (2005-09-20 22:06) [5]

kami ©   (20.09.05 21:29) [3]
Всё это звучит весьма достойно но страшно, я не очень разбираюсь в сетевых вопросах прошу доступный для понимания пример(желательно с пояснениями), спасибо.


 
Delphi_is_cool ©   (2005-09-21 00:53) [6]

Ставь между сообщениями пробел ? )


 
kami ©   (2005-09-21 01:04) [7]

> но страшно

А чего тут страшного ? Сам пару месяцев назад так думал.

Пример...
Предполагаю, что соединение ClientSocket - ServerSocket уже установлено, отправка производится с клиента на сервер, тогда :

type
 TMyData=record
   Length:Word;// здесь будет храниться длина пересылаемой строки
   //---------- другая необходимая информация
   myText:string;
 end;
 //-----------------------------------
 MyStream:TMemoryStream;
 procedure MySendText(MyText:string);

// где создать MyStream - без понятия, например, в FormCreate, тогда уничтожить - в FormDestroy

procedure MySendText(MyText:string);
var
 MyData:TMyData;
begin
 MyData.Length:=Length(MyText);
 MyData.myText:=MyText;{в принципе,это все лишнее,если структура TMyData ограничится только этими полями}
 ClientSocket.Socket.SendBuf(MyData.Length);
 ClientSocket.Socket.SendBuf(MyData.myText[1],MyData.Length);
end;

{ пересылать вот так, непосредственно буфером тоже не совсем верно - при заполнении буфера самого сокета может не отослаться, реализация такой защиты в http://delphimaster.net/view/6-1122136315/ }

на сервере в OnClientRead:
var
 Buf:Array of byte;// временный массив, куда "запихнем" всё, что прислали с клиента
 Size:integer;// размер принятой информации
 MyData:TMyData;// сюда "складываем" принятые строки (по очереди)
 TempStream:TMemoryStream;//совсем временный поток :)
begin
 Size:=Socket.ReceiveLength;
 SetLength(Buf,Size);
 Socket.ReceiveBuf(Buf[0],Size);

 MyStream.Seek(0,soFromEnd)//добавляем данные в буфер FIFO, которым является MyStream
 MyStream.Write(Buf[0],Size);
 { теперь в MyStream содержатся все данные принятые прежде и не выбранные (по причине того, что приняты не полностью) + принятые сейчас в формате: длина строки | содержание строки}

 // начинаем выборку
 repeat
   if MyStream.Size<SizeOf(Word){ + минимальный_размер_длинной_строки } then
     break;// больше выбирать нечего, все данные закончились
   MyStream.Read(MyData.Length,SizeOf(Word));  // считали длину строки
   if (MyStream.Size-MyStream.Position)>=MyData.Length then
   { если запись, которую пытаемся выбрать, пришла полностью, то можно продолжить выборку текущей записи}
     begin
       SetLength(MyData.myText,MyData.Length);
       MyStream.Read(MyData.myText[1],MyData.Length);
       { запись считана, теперь нужно удалить ее из потока}
       { следующий код - далеко не лучшее решение, но сейчас в голову ничего не приходит}
       TempStream:=TMemoryStream.Create;
       TempStream.CopyFrom(MyStream,MyStream.Size-MyStream.Position);//скопируем все, кроме уже считанного
       MyStream.Clear;
       MyStream.LoadFromStream(TempStream);// и занесем обратно
       TempStream.Free;
       DoSomethingWithString(MyData.myText);// вместо этого - реальный обработчик пришедшей строки
     end
   else
     break;//строка, до которой дошли, пришла не полностью, будем ждать следующего пакета, чтобы дополнить недостающее
 until False;
end;


ЗЫ. Писалось по памяти, без Delphi, так что могут быть некоторые ошибки. Но общий принцип - примерно такой.


 
kami ©   (2005-09-21 01:09) [8]

Упс...
 Сразу после repeat :
MyStream.Position:=0;



Страницы: 1 вся ветка

Текущий архив: 2006.01.01;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.032 c
14-1133712022
vladik
2005-12-04 19:00
2006.01.01
проблема при установки системы


14-1133860176
Andrewmx
2005-12-06 12:09
2006.01.01
Работа с очередью


14-1133991117
beglec
2005-12-08 00:31
2006.01.01
вопрос по геометрии


2-1134421386
Pupsiks
2005-12-13 00:03
2006.01.01
Сообщение


1-1133516273
КК
2005-12-02 12:37
2006.01.01
В Excel из Delphi