Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 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.026 c
14-84649
off
2003-06-10 11:26
2003.06.26
Эмуляция нажатия клавиши в нужном приложении?


14-84685
passlight
2003-05-23 09:56
2003.06.26
---|Ветка была без названия|---


3-84002
AlexBut
2003-05-29 06:39
2003.06.26
Код ошибки Jet


3-83950
first_aid
2003-06-04 08:56
2003.06.26
Как используя компоненты ADO создать базу данныз Access?


14-84599
Mr.Harry
2003-06-09 01:53
2003.06.26
Непонятка...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский