Блин, народ разъясните кому не лень. Ни как не пойму...
Клиент отправляет сразу после подключения:
type
TPrefix=record
CMD: Integer;
Size: Integer;
end;
procedure TfMain.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var Prefix: TPrefix;
ClientNo: String;
begin
if Socket.Connected then
begin
Prefix.CMD:=CMD_LOGIN;
Prefix.Size:=6;
ClientSocket1.Socket.SendBuf(Prefix,SizeOf(Prefix));
ClientNo:=C_CLIENTNO;
ClientSocket1.Socket.SendBuf(ClientNo,Prefix.Size);
end;
end;
сервер принимает:
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var ClientNo: String;
SocketData: TclAssoc;
Prefix: TPrefix;
begin
Socket.ReceiveBuf(Prefix,Socket.ReceiveLength);
case Prefix.CMD of
{CMD_LOGIN} 0:begin
SetLength(ClientNo,Prefix.Size);
Socket.ReceiveBuf(ClientNo,Prefix.Size);
ShowMessage('CMD_LOGIN');
ShowMessage(ClientNo);
ShowMessage(IntTosTr(Length(ClientNo)));
end;
2:;
end;
end;
При вызове SendBuf(ClientNo...) доставляется все как задумано
При вызове SendBuf(ClientNo...) на сервере принимается какая то лабуда...
Re: ReceiveBuf Delphi7
От:
Аноним
Дата:
31.05.11 11:06
Оценка:
Здравствуйте, molinero, Вы писали:
M>Блин, народ разъясните кому не лень. Ни как не пойму...
M>Клиент отправляет сразу после подключения:
M>type M> TPrefix=record M> CMD: Integer; M> Size: Integer; M> end;
Во-вторых,
кто обещал что Socket.ReceiveBuf(Prefix,Socket.ReceiveLength);
примет ровно SizeOf(TPrefix ) байт?
может придти и меньше и больше,
в случае меньше — накапливаем в буфер, пока не придет как минимум сколько нужно,
как дождались или в случае больше или равно
накладываем на буфер указатель (PPrefxix) структуры, читаем структуру,
продвигаемся по буферу (или откусываем голову)
M>При вызове SendBuf(ClientNo...) на сервере принимается какая то лабуда...
Re[2]: ReceiveBuf Delphi7
От:
Аноним
Дата:
01.06.11 04:59
Оценка:
А>в случае меньше — накапливаем в буфер, пока не придет как минимум сколько нужно, А>как дождались или в случае больше или равно А>накладываем на буфер указатель (PPrefxix) структуры, читаем структуру, А>продвигаемся по буферу (или откусываем голову)
А как в буфер то напкопить?
var Buf: Pointer;
Prefix: TPrefix;
ReceiveLength: Integer;
begin
ReceiveLength:=0;
if Socket.ReceiveLength>=SizeOf(TPrefix)then
Socket.ReceiveBuf(Buf^,SizeOf(TPrefix))
else
begin
while ReceiveLength<=SizeOf(Tprefix)do
begin
Socket.ReceiveBuf(Buf^,Socket.ReceiveLength);
ReceiveLength:=+Socket.ReceiveLength;
end;
end;
Prefix:=PTPrefix(Buf)^;
Если длать так, то Buf будет перезаписваться и указывать на адрес новой порции данных?
Как мне добавитьв буфер?
В Prefix записывается то что я отправил, но в конце процедуры ошибка доступа к памяти.
А>>в случае меньше — накапливаем в буфер, пока не придет как минимум сколько нужно, А>>как дождались или в случае больше или равно А>>накладываем на буфер указатель (PPrefxix) структуры, читаем структуру, А>>продвигаемся по буферу (или откусываем голову)
А>А как в буфер то напкопить?
А>var Buf: Pointer; А> Prefix: TPrefix; А> ReceiveLength: Integer; А>begin А> ReceiveLength:=0; А> if Socket.ReceiveLength>=SizeOf(TPrefix)then А> Socket.ReceiveBuf(Buf^,SizeOf(TPrefix)) А> else А> begin А> while ReceiveLength<=SizeOf(Tprefix)do А> begin А> Socket.ReceiveBuf(Buf^,Socket.ReceiveLength); А> ReceiveLength:=+Socket.ReceiveLength; А> end; А> end; А> Prefix:=PTPrefix(Buf)^;
А>Если длать так, то Buf будет перезаписваться и указывать на адрес новой порции данных? А>Как мне добавитьв буфер? А>В Prefix записывается то что я отправил, но в конце процедуры ошибка доступа к памяти.
Правильно, Вы ведь буфер не аллоцируете нигде.
Пользуясь для простоты строкой как буфером (не самое плохое решение, между прочим), делаем примерно так:
type
TclAssoc = ... ваша структура или объект, ассоциированный с сокетом
...
sInputBuffer : ansistring;
...
end;
type
PPrefix=^TPrefix;
TPrefix = packed record
CMD : Integer;
Size : Integer; // я правильно понимаю, что это размер хвоста посылки после префикса?end;
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
SocketData: TclAssoc;
ptrPrefix: PPrefix;
totalPackSize : cardinal;
sReadPart: ansistring;
sClientNo: ansistring;
begin// получаем ассоциированную с сокетом структуру данных
SocketData := GetSocketDataBySocket(Socket); <= тут я не знаю как у вас связь сделана
// читаем кусок данных
SetLength(sReadPart, Socket.ReceiveLength);
Socket.ReceiveBuf(sReadPart[1], Length(sReadPart));
// добавляем прочитанный кусок к общему буферу
SocketData.sInputBuffer := SocketData.sInputBuffer + sReadPart;
// разбираем принятые пакетыwhile (Length(SocketData.sInputBuffer) > 0) do begin// если данных совсем мало, даже на хидер не хватает, то перестанем
// тут крутиться и пойдем нафик, ждем когда дошлют еще данныхif (Length(SocketData.sInputBuffer) < SizeOf(TPrefix)) then Break;
// заголовок пришел, проверим, весь-ли хвост имеем.
// в принципе, можно обработать и только заголовок, но сейчас для
// простоты будем ждать посылку целиком
ptrPrefix := @SocketData.sInputBuffer[1];
totalPackSize := (SizeOf(TPrefix) + ptrPrefix^.Size);
if (Length(SocketData.sInputBuffer) < totalPackSize) then Break;
// если мы еще здесь, то как минимум одна посылка уже имеется целиком, обработаемcase Prefix.CMD of{CMD_LOGIN} 0: begin
sClientNo := Copy(SocketData.sInputBuffer, SizeOf(TPrefix) + 1, ptrPrefix^.Size);
ShowMessage(Format('CMD_LOGIN %s %d', [sClientNo, Length(sClientNo)])); // не очень хорошо тут мессаджи показывать...end;
2: ;
end;
// убрать обработанную посылку из буфера
Delete(SocketData.sInputBuffer, 1, totalPackSize);
// тут возвращаемся к началу цикла - возможно в буфере есть еще посылкиend;
end;
Здравствуйте, Аноним, Вы писали:
А>Пользуясь для простоты строкой как буфером (не самое плохое решение, между прочим), делаем примерно так:
В качестве буфера можно использовать TMemoryStream?
Re[5]: ReceiveBuf Delphi7
От:
Аноним
Дата:
01.06.11 11:10
Оценка:
Здравствуйте, molinero, Вы писали:
А>> ShowMessage(Format('CMD_LOGIN %s %d', [sClientNo, Length(sClientNo)])); // не очень хорошо тут мессаджи показывать...
M>Такие сообщения я кое где вставляю для проверки результатов... А чем это чревато?
M>Я правильно понимаю, что если отправить два сообщения подряд, к примеру,
M>
M>То на приемнике возникнет два события OnClientRead? Или все же одно?
Это вам теорию почитать про ТСР протокол нужно.
Запись в поток, чтение из потока, фрагментация и там и там — вам практически неподвластна,
думайте о потоке байтов а не о пакетах, каждый сетевой уровень может разбивать-собирать
фрагменты по своим правилам, ваш вызов recv не обязательно даст вам столько сколько
запрошено, может и меньше.
TMemoryStream использовать можно, но будет немного затруднительно откусывать обработанную голову
вариант со строками вполне приемлим на небольших (до 4к) посылках, если больше и нужна
хорошая производительность — нужно разрабатывать альтернативные методы.
Например, кольцевой зеркальный, или массив или дерево буферов, но тут усложняется
манипулирование и доступ. Или комбинированный — строка для заголовков и стрим для хвоста.