![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Сокеты "склеивают" сообщения! [D7, WinXP]
Galiaf © (2005-09-20 20:31:00)Драсти. Проблема такая: если очень быстро послать сокетом текст 'привет' то придёт он в таком виде 'приветпривет' :(.
Не катит!
Помогите с проблемой разобраться, как отправлять что бы не склеивало, потому что отправлять придётся много и быстро, это будет использоваться в сетевой игре и отсылать буду очень важные данные.
kami (2005-09-21 01:09:00) [1]Упс...
Сразу послеrepeat :
MyStream.Position:=0;
kami (2005-09-21 01:04:00) [2]> но страшно
А чего тут страшного ? Сам пару месяцев назад так думал.
Пример...
Предполагаю, что соединение 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://www.delphimaster.ru/cgi-bin/forum.pl?id=1122136315&n=4}
на сервере в 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=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, так что могут быть некоторые ошибки. Но общий принцип - примерно такой.
Delphi_is_cool (2005-09-21 00:53:00) [3]Ставь между сообщениями пробел ? )
Galiaf (2005-09-20 22:06:00) [4]kami © (20.09.05 21:29) [3]
Всё это звучит весьма достойно но страшно, я не очень разбираюсь в сетевых вопросах прошу доступный для понимания пример(желательно с пояснениями), спасибо.
XProger (2005-09-20 22:01:00) [5]http://xproger.mirgames.ru/files/lib/l_net.rar
Библиотека готового сетевого протокола основанного на UDP. Имеется реализация гарантированной доставки пакетов, а также широковещательные рассылки. Прилагается пример чата. Прирост к исполняемому файлу составляет 5.5 кб!
kami (2005-09-20 21:29:00) [6]
> что бы не склеивало
1.Посылать перед каждым текстом его длину [ другую служебную информацию ]
2.Сохранять всёпринятое в конецMemoryStream
3.Просматривать с начала MemoryStream после каждого приема, выбирая пришедшие полностью сообщения и, соответственно, удаляя их из потока.
Это защитит не только от склеивания, но и от разбиения по пакетам.
Galiaf (2005-09-20 21:22:00) [7]Отправлял я по нажатию на Enter но без строки "ActiveControl := Edit13;", а что она делает?
KLAUS (2005-09-20 20:47:00) [8]А ты как вообще отправляешь?
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Socket.SendText(Edit1.Text);
Edit13.Text := '';
ActiveControl := Edit13;
end;