Форум: "Сети";
Текущий архив: 2003.06.26;
Скачать: [xml.tar.bz2];
ВнизWinSocket. Как узнать что послано текст или данные ? Найти похожие ветки
← →
SergeyI (2003-04-23 11:50) [0]Как узнать что послано текст или данные ?
те какой функцией получать данные Socket.ReceiveBuf или
socket.ReceiveText
← →
Digitman (2003-04-23 12:05) [1]
> Как узнать что послано текст или данные
а протокол информационного обмена для какой цели, по твоему, разрабатывается для каждого конкретного отдельно взятого сервиса ? будь то HTTP, FTP, SMTP, POP3, ICQ или что-то еще ?
именно в соответствии с конкретным протоколом информационного обмена каждая из обменивающихся сторон имеет возможность знать, приема какого типа данных следует ожидать от партнера в каждый конкретный момент времени при конкреных условиях
> какой функцией получать данные Socket.ReceiveBuf или
> socket.ReceiveText
Любой. ReceiveText внутри себя вызывает ReceiveBuf. Разницы, по сути - никакой. Так что лучше всего вообще не пользовать ReceiveText, а вызывать сразу ReceiveBuf. Единственное отличие - ReceiveText самостоятельно организует локальный буфер приема в виде строки, размер которой устанавливается по фактически прочитанным данным. При этом фактически записанные в буфер строки данные никак не проверяются на тот признак, текст это или что-то еще.
← →
SergeyI (2003-04-23 12:22) [2]Спасибо за ответ а можно получить совет на тему "как лучше сделать" задача такая клиент может посылать запросы-команды (я думал сделать их строками) и данные, на сервере надо отличать первое от второго
← →
Digitman (2003-04-23 12:35) [3]клиент, например, может послать запрос-команду фикс.размера (скажем, dword), следом - размер сопровождающих команду данных (скажем, тоже dword), следом - собственно данные
сервер в этом случае знает, что, приняв первый dword он получает код команды, следующий dword - размер возможно сопровождающих команду данных, далее (имея уже размер данных, если он - ненулевой) считывает из гнезда ровно столько данных, сколько заявил клиент во 2-м (по очереди считывания) dword"е.
← →
SergeyI (2003-04-23 12:53) [4]идея понятна только зачем передавать размер ? если имхо его можно получить Socket.ReceiveLength - sizeof(dword) или нельзя ?
← →
Digitman (2003-04-23 13:11) [5]
> если имхо его можно получить Socket.ReceiveLength
а что по твоему означает ReceiveLength ? каков его фактический смысл в твоем понимании ?
← →
Akni (2003-04-23 13:34) [6]> клиент, например, может послать запрос-команду фикс.размера (скажем, dword), следом - размер сопровождающих команду данных (скажем, тоже dword), следом - собственно данные
именно так я и пытаюсь сделать:
type ISRecDat=record
...
end;
на сервере
var GlobalDat: ISRecDat;
procedure TISServerThread.SendData(var Msg: TMessage);
var iCode: integer;
begin
if fServerSocket.Socket.ActiveConnections>0 then
begin
iCode:=cdRec;
fServerSocket.Socket.Connections[0].SendBuf(iCode, sizeOf(iCode));
fServerSocket.Socket.Connections[0].SendBuf(GlobalDat, SizeOF(ISRecDat));
end;
end;
на клиенте
var GlobalDat1: ISRecDat;
iRecvdCode: integer;
procedure TISClientThread.SocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var iRecvdLen: Integer;
iRecvdSize: integer;
iCode: integer;
begin
iRecvdLen := Socket.ReceiveLength;
if iRecvdLen>0 then
if iRecvdCode=cdNONE then //получить код
begin
Socket.ReceiveBuf(iRecvdCode, SizeOf(iRecvdCode));
end;
case iRecvdCode of
cdREC:
begin
Socket.ReceiveBuf(GlobalDat1, SizeOf(ISRecDat)); //получить данные
iRecvdCode:=cdNONE; //занулить код
end;
end;
end;
Но данные не приходят одним блоком того же размера, как были посланы.
Является ли хорошим решением в данном случае использовать поток (TMemoryStream) и писать в него данные, пока этих данных не наберется опред. кол-во (напр. SizeOf(ISRecDat) или SizeOf(Integer)) а потом уже читать из потока в соответствующие переменные?
← →
Digitman (2003-04-23 13:48) [7]
> Akni
> Но данные не приходят одним блоком того же размера, как
> были посланы
разумеется ! протокол-то - поточный)
> Является ли хорошим решением в данном случае использовать
> поток (TMemoryStream) и писать в него данные, пока этих
> данных не наберется опред. кол-во (напр. SizeOf(ISRecDat)
> или SizeOf(Integer)) а потом уже читать из потока в соответствующие
> переменные?
как тебе будет удобней и проще реализовать прием и анализ принятого на соответствие протоколу инф.обмена (с пом. стрима или иным способом) - в конечном счете решать тебе : никаких ограничений нет
но, в принципе, использование мемстрима для этой цели есть не самое худшее решение.
здесь гораздо важней другое - реализовать нечто вроде "машины логического состояния транспорта" : что в данный момент ожидается/считывается из буфера (статус = 1.команда/2.размер/3.данные), сколько еще осталось принять данных для переключения в следующий по логике инф.обмена статус и т.д.
← →
Akni (2003-04-23 14:16) [8]>(с пом. стрима или иным способом)
а какие еще есть другие способы? у меня, честно говоря мемстрим - единственная идея пока
> реализовать нечто вроде "машины логического состояния транспорта"
это понятно
еще один вопрос - можно ли анализировать мемстрим прямо в OnRead? Не может ли произойти так, что пока я разбираюсь со стримом, пришли новые данные, а сокет не готов их принять, т.к. он все еще находится в обработчике OnRead и занят предыдущей порцией данных? Если да, то как с этим бороться?
← →
Polevi (2003-04-23 14:27) [9]OnRead должен работать быстро
← →
Digitman (2003-04-23 14:32) [10]совершенно верно Polevi говорит : обработчик OnRead() должен как можно быстрей быть выполненным.
Да и не только OnRead() ! Любой обработчик события должен выполняться насколько это возможно быстро. При этом совершенно неважно, к каком код.потоке он вызывается
← →
Akni (2003-04-23 16:17) [11]А можно поконкретнее, что значит "быстро"? Я сама понимаю, что считать в обработчике простые числа, наверное, не стоит :)
Но хотелось бы узнать ваше мнение, является ли приемлимым след. код.
procedure TISClientThread.SocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var iRecvdLen: Integer;
iRecvdSize: integer;
iAllSize: integer;
Buffer: Pointer;
Dat: ISRecDat;
begin
iAllSize:=0;
iRecvdLen := Socket.ReceiveLength;
if iRecvdLen>0 then
repeat
if iRecvdCode=cdNONE then
begin
GetMem(Buffer, SizeOf(iRecvdCode));
try
iRecvdSize:=Socket.ReceiveBuf(Buffer^, SizeOf(iRecvdCode));
iAllSize:=iAllSize+iRecvdSize;
fMemStream.Write(Buffer^,iRecvdSize);
if fMemStream.Size=SizeOf(iRecvdCode) then
begin
fMemStream.Seek(0,soFromBeginning);
fMemStream.ReadBuffer(iRecvdCode, SizeOf(iRecvdCode));
fMemStream.Clear;
end;
finally
FreeMem(Buffer);
end;
end;
case iRecvdCode of
cdREC:
begin
GetMem(Buffer, SizeOf(ISRecDat));
try
iRecvdSize:=Socket.ReceiveBuf(Buffer^, SizeOf(ISRecDat));
iAllSize:=iAllSize+iRecvdSize;
fMemStream.Write(Buffer^,iRecvdSize);
if fMemStream.Size=SizeOf(ISRecDat) then
begin
fMemStream.Seek(0,soFromBeginning);
fMemStream.ReadBuffer(Dat, SizeOf(ISRecDat));
PostMessage(fFrm.Handle,wm_RefreshClients,cdREC,0);
iRecvdCode:=cdNONE;
fMemStream.Clear;
end;
finally
FreeMem(Buffer);
end;
...
end;
end;
until (iAllSize=iRecvdLen) or (iRecvdSize<=0);
end;
На двух машинах в одной подсети работает; не хотелось бы, чтобы возникли проблемы при переносе в большую систему.
← →
Digitman (2003-04-23 16:41) [12]вот такая транспортная логика работает у меня, и - вполне успешно в уловиях глоб.сети :
procedure TSocketTransport.ReadEventHandler(Sender: TObject; Socket: TCustomWinSocket);
var
FRecvBuf: PByteArray;
FRcvBufSize: Integer;
NumOfBytesRead: Integer;
begin
FRcvBufSize := Socket.ReceiveLength;
if FRcvBufSize = 0 then Exit;
GetMem(FRecvBuf, FRcvBufSize);
try
try
NumOfBytesRead := Socket.ReceiveBuf(FRecvBuf, Min(FExpectedBytesToRead, FRcvBufSize));
while NumOfBytesRead > 0 do
begin
Dec(FExpectedBytesToRead, NumOfBytesRead);
case FRecvState of
rsSignature: //статус - прием сигнатуры
if FExpectedBytesToRead = 0 then
begin
if (PInteger(FRecvBuf)^ and CallSig <> CallSig) and
(PInteger(FRecvBuf)^ and ResultSig <> ResultSig) then
raise Exception.CreateRes(@SInvalidDataPacket);
FIncomingDataBlock := TDataBlock.Create as IDataBlock;
FIncomingDataBlock.Signature := PInteger(FRecvBuf)^;
FExpectedBytesToRead := SizeOf(DWord);
FRecvState := rsContext;
end;
rsContext: //статус - прием идент-ра тек.контекста
if FExpectedBytesToRead = 0 then
begin
FIncomingDataBlock.Context := PInteger(FRecvBuf)^;
FExpectedBytesToRead := SizeOf(DWord);
FRecvState := rsSize;
end;
rsSize: //
← →
Polevi (2003-04-23 17:12) [13]2Digitman © (23.04.03 16:41)
FRcvBufSize := Socket.ReceiveLength;
я тоже так делаю, однако Э.Джонс в "Программирование в сетях Microsoft Windows" этого не рекомендует - мотивирует тем что лишний раз приходится пробегать по очереди пакетов в буфере winsock, с его точки зрения правильнее запросить столько данных, сколько требуется и анализировать их прочитанное колво
← →
Digitman (2003-04-24 08:35) [14]
> Polevi
трассировкой мне удалось локализовать вызов в недрах ReceiveLength() ф-ции ядра ZwDeviceIoControlFile() (та же самая ф-ция вызывается и в любом из recv-методов, но с иними параметрами)... собственно эта ф-ция в дан.случае и возвращает размер потенциально доступных данных... ф-ция входит в шлюз Int2E и далее ее логика выполняется в 0-м кольце привелегий, так что пока сказать трудно по поводу сканирования...
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2003.06.26;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.043 c