Форум: "Сети";
Текущий архив: 2006.01.01;
Скачать: [xml.tar.bz2];
ВнизСокеты "склеивают" сообщения! Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.009 c