Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2003.01.13;
Скачать: [xml.tar.bz2];

Вниз

Передача данных при помощи сокетов.   Найти похожие ветки 

 
V_Pavel   (2002-11-01 12:27) [0]

Мне нужно организовать обмен данными между клиентом и сервером при помощи сокетов. Как и с помощью чего это лучше сделать чтоб работало надежно? Предполагаемый размер пакетов колеблется от 10 байт до 500 килобайт. Данные нужно передавать как с клиента на сервер так и обратно. Если у кого есть примеры или ссылки на примеры поделитесь буду рад. Я побывал это делать при помощи стандартных компанент работает но не устойчива, а именно если после большого пакета размером примерно 50 кб. передаю пакет размером 10 байт он кудато теряется.


 
Digitman   (2002-11-01 12:55) [1]


> побывал это делать при помощи стандартных компанент работает
> но не устойчива


Некорректен именно твой код, а не внутренняя работа этих компонентов


 
Song   (2002-11-01 13:03) [2]

http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1036137108&n=4


 
V_Pavel   (2002-11-01 13:31) [3]

да я согласен что мой код некорректен.
Вот посмотрите и скажите что не так. Данный код при приеме склеивает пакет из нескольких кусков в один и при наличии в начале первого куска информации о длине пакета и проверяет куски на наличие склеенных пакетов.
Если после передачи большого пакета сервером проходит немного времени перед передачей маленького пакета то все нормально а вот если сразу передается маленький пакет по он теряется в 3-5 случаях из 10.
procedure TFmain.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
count :Integer;
buffer: Array [0..MAX_BUF_SIZE] of Char;
p:tstringstream;
i,ln:integer;
str:string;

begin
i:=0;
p:=tstringstream.Create("");
Socket.Lock;
repeat
count:= Socket.ReceiveBuf(buffer,SizeOf(buffer));
if count > 0 then
begin
p.WriteBuffer(buffer,count);
if i=0 then ln:=strtoint(copy(p.DataString,1,10)));
if p.Size>=ln then
repeat
str:=p.DataString;
ln:=strtoint(copy(str,1,10));
decodePacket(copy(str,1,ln+10)); {обработчик пакета}
p.free;
delete(str,1,ln+10);
p:=tstringstream.Create(str);
i:=0;
until (p.Size<10)
else inc(i);
end;
Socket.Unlock;
until (count <= 0);
dePacket(p.DataString);
p.Free;
end;


 
Digitman   (2002-11-01 13:48) [4]

ПРиведи еще код передатчика


 
V_Pavel   (2002-11-03 17:07) [5]

Вот передатчик.
procedure sendpacket(str:string;sh:integer;Socket: TServerWinSocket);
var i,ind:integer;
head:string;
begin
if sh=0 then ind:=0 else
for i:=0 to socket.ActiveConnections-1 do
if socket.Connections[i].Handle=sh then ind:=i;
head:=padl(inttostr(length(str)+10),10,"0");
socket.Connections[ind].SendText(head+str);
end;

Если слать одинаковые пакеты то они не теряются а вот если слать сперва большой пакет а потом маленький то маленький не доходит. Я пробывал ставить задержку между посылками хотябы на 10 ms. тогда вроде рабтает.


 
Digitman   (2002-11-04 08:26) [6]

>V_Pavel

Где анализ результата, возвращаемого ф-цией
socket.Connections[ind].SendText(head+str) ?

Где обработка события OnClientWrite ?


 
V_Pavel   (2002-11-04 09:16) [7]

Digitman © , что ты посоветуешь сделать. Я с сетями работаю не так давно и еще не сильно разбираюсь. Подскажи хоябы идею по обработке результата, возвращаемого ф-цией socket.Connections[ind].SendText(head+str) и что нужно написать в обработчике события OnClientWrite.


 
Digitman   (2002-11-04 10:29) [8]

Я посоветую для начала внимательно почитать хэлп на метод TCustomWinSocket.SendText() и на событие TCustomWinSocket.OnWrite(). Результат вызова метода SendText() (как и прочих иных send-методов) говорит о многом, в зависимости от результата дальнейшие действия могут быть тесно связаны с необходимостью выполнения повторной передачи тех же данных в момент возникновения события OnWrite().

Imho, самый удобный, наглядный и наименее проблематичный способ передачи данных в асинхр.неблок.режиме - это передача с использованием поточного класса TStream.

Примерный вариант :


//тело обработчика OnClientConnect()
Socket.Data := nil;

//тело обработчика OnClientDisconnect()
if Assigned(Socket.Data) then
TMemoryStream(Socket.Data).Free;

//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
Stream := Socket.Data;
if not Assigned(Stream) then
Stream := TMemoryStream.Create;
CurStreamReadPos := Stream.Position;
Stream.Write(...то что нужно передать...);
Stream.Position := CurStreamReadPos;
if not Assigned(Socket.Data) and not Socket.Connections[index].SendStream(Stream) then
begin
Socket.Data := Stream;
Процедура_обработчика_OnClientWrite(ServerSocket, Socket);
end

//тело обработчика OnClientWrite()
var Stream: TMemoryStream; //лок.переменная
...
Stream := TMemoryStream(Socket.Data);
if Assigned(Stream) and Socket.SendStream(Stream) then
Socket.Data := nil;




 
Digitman   (2002-11-04 10:36) [9]

вернее - вот так :


//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
Stream := Socket.Data;
if not Assigned(Stream) then
Stream := TMemoryStream.Create;
CurStreamReadPos := Stream.Position; //тек.позиция считывания из потока
Stream.Position := Stream. Size; //в конец потока
Stream.Write(...то что нужно передать...); //в хвост потока - новые данные
Stream.Position := CurStreamReadPos; //восстановление тек.позиции
if not Assigned(Socket.Data) and not Socket.Connections[index].SendStream(Stream) then
begin
Socket.Data := Stream;
Процедура_обработчика_OnClientWrite(ServerSocket, Socket);
end


 
Digitman   (2002-11-04 10:43) [10]

и вот еще поправка :

//тело обработчика OnClientDisconnect()
if Assigned(Socket.Data) then
try
TMemoryStream(Socket.Data).Free;
except
end



 
V_Pavel   (2002-11-04 12:23) [11]

Спасибо за пример!
У меня по нему 2 вопроса.
1)
//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
Stream := Socket.Data;
а если тут сделать так
Stream := Socket.Connections[index].Data;
я думаю будет правильнее или я ощибаюсь.
2)И мне не совсем понятен код

if not Assigned(Socket.Data) and not Socket.Connections[index].SendStream(Stream) then
begin
Socket.Data := Stream;
Процедура_обработчика_OnClientWrite(ServerSocket, Socket);
end






 
Digitman   (2002-11-04 12:32) [12]


> а если тут сделать так
> Stream := Socket.Connections[index].Data;
> я думаю будет правильнее или я ощибаюсь.


Да, так будет правильно.


> И мне не совсем понятен код


Что тебе непонятно ? Конкретно ?


 
V_Pavel   (2002-11-04 13:20) [13]

Может я чтото не понимаю но объясни мне это место
if not Assigned(Socket.Data) and not Socket.Connections[index].SendStream(Stream) then


 
V_Pavel   (2002-11-04 13:30) [14]

>if not Assigned(Stream) then
> Stream := TMemoryStream.Create;
Тут мы создаем поток а где мы его убиваем?


 
Digitman   (2002-11-04 13:46) [15]

Вот так корректней будет.


//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var Target: TCustomWinSocket; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
Target := Socket.Connections[index]; // целевое гнездо
Stream := Target.Data;
if not Assigned(Stream) then
Stream := TMemoryStream.Create;
CurStreamReadPos := Stream.Position; //тек.позиция считывания из потока
Stream.Position := Stream.Size; //в конец потока
Stream.Write(...то что нужно передать...); //в хвост потока - новые данные
Stream.Position := CurStreamReadPos; //восстановление тек.позиции
if not Assigned(Target.Data) then // если очередь передачи пуста
begin
Socket.Data := Stream; // ставим поток в очередь
Процедура_обработчика_OnClientWrite(ServerSocket, Target); // инициируем передачу очереди
end



Теперь понятно ?


 
Digitman   (2002-11-04 13:48) [16]


> Тут мы создаем поток а где мы его убиваем?


Хэлп-то читать будем когда-нибудь ?
Читай внимательно описание SendStream() :

Note: The Stream passed as a parameter to SendStream becomes “owned” by the windows socket object. The Windows socket object frees the stream when it is finished with it. Do not attempt to free the stream after it has been passed as a parameter.


 
V_Pavel   (2002-11-04 14:11) [17]

Спасибо за разъяснения. Теперь все понятно. Вечером попробую запихнуть это все в свой проект. А там посмотрим что получиться.
Надеюсь будет работать как надо. Еще раз спасибо.


 
V_Pavel   (2002-11-05 06:13) [18]

Передатчик вроде работает нормально, но теперь придется переписать приемник. Digitman ©, не подскажешь как это правильнее сделать.


 
Digitman   (2002-11-05 08:25) [19]

Приведи спецификацию своего собственного протокола инф.обмена, тогда и разговор будет


 
V_Pavel   (2002-11-05 11:48) [20]

Нужно передать от сервера клиенту абстрактный поток данных (файл, текст, картинка неважно). В начале потока в первых 10 байтах передавать его длину. Клиент считывает длину и все последующие блоки склеивает в один пока длина получившегося блока не равна длине передаваемых данных. Когда клиент получил этот поток он решает что с ним делать.


 
Digitman   (2002-11-05 14:02) [21]

Куда тебе столько - аж 10 байт ?)
10-ю байтами можно описать число до 1208925819614629174706175 включительно ) ... Астрономическое почти число !)

Практически же для любых передаваемых объектов вполне достаточно и 4-х байт



type
TTransportState = (tsDataSizeReceiving, tsDataBlockReceiving);

var
TransportState: TTransportState = tsDataSizeReceiving;
TotalDataSizeBytesRead: DWord = 0;
TotalDataBlockBytesRead: DWord = 0;
TotalBlockSize: DWord = 0;
DataBlock: Pointer;


function DoReadDataSize(Socket: TCustomWinSocket): Boolean;
var
BytesRemains: DWord,
ActualBytesRead : Integer;
buf: Pointer;
begin
BytesRemains := SizeOf(DWord) - TotalDataSizeBytesRead;
if BytesRemains > 0 then
begin
buf := Pointer(DWord(@TotalBlockSize) + TotalDataSizeBytesRead);
ActualBytesRead := Socket.ReceiveBuf(buf^, BytesRemains);
if ActualBytesRead <> - 1 then
Inc(TotalDataSizeBytesRead, ActualBytesRead);
end;
Result := TotalDataSizeBytesRead = SizeOf(DWord);
end;

function DoReadDataBlock(Socket: TCustomWinSocket): Boolean;
var
BytesRemains: DWord,
ActualBytesRead : Integer;
buf: Pointer;
begin
if not Assigned(DataBlock) then
GetMem(DataBlock, TotalBlockSize);
try
BytesRemains := TotalBlockSize - TotalDataBlockBytesRead;
if BytesRemains > 0 then
begin
buf := Pointer(DWord(DataBlock) + TotalDataBlockBytesRead);
ActualBytesRead := Socket.ReceiveBuf(buf^, Min(BytesRemains, 4096));
if ActualBytesRead <> - 1 then
Inc(TotalDataBlockBytesRead, ActualBytesRead);
end;
Result := TotalDataBlockBytesRead = TotalBlockSize;
except
FreeMem(DataBlock);
DataBlock := nil;
raise;
end;
end;

procedure DoProcessDataBlock(DataBlock, TotalBlockSize);
begin
try
// ... обработка блока ...
finally
FreeMem(DataBlock);
DataBlock := nil;
end;
end;

procedure TFmain.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
case TransportState of
tsDataSizeReceiving:
if DoReadDataSize(Socket) then
begin
TotalDataBlockBytesRead := 0;
TransportState := tsDataBlockReceiving;
end;
tsDataBlockReceiving:
if DoReadDataBlock(Socket) then
try
DoProcessDataBlock(DataBlock, TotalBlockSize);
TotalDataSizeBytesRead := 0;
TransportState := tsDataSizeReceiving;
finally
DataBlock := nil;
end;
end;
begin
end;



 
daan_m   (2002-11-06 11:39) [22]

На сколько я знаю:1) Данные разбиваются на пакеты;2) Каждый пакет весом 8 кило3) Вместе с пакетами идут флаги один из них говорит, что пакет последний.4) Разработчики Delphi не сочли нужным анализировать эти флаги:(5) НО на API уровне анализ возможен.


 
Digitman   (2002-11-06 11:56) [23]

> 1) Данные разбиваются на пакеты;

На уровне IP-протокола - да

> 2) Каждый пакет весом 8 кило
Не пакет, а буфер очереди передачи. И - необязательно. Это значение в большинстве реализайий WinSock - по-умолчанию, но делать на это безусловную ставку некорректно.

> 3) Вместе с пакетами идут флаги

Все это на уровне IP-транспорта.

> 4) Разработчики Delphi
> не сочли нужным анализировать эти флаги

Это не их забота. Это - забота разработчиков кода, реализующего TDI и OSI

> (5) НО на API уровне анализ возможен.

На уровне WinsockAPI - нет. Это - высокоуровневая надстройка над низкоуровневыми транспортными сетевыми протоколами


 
V_Pavel   (2002-11-08 16:08) [24]

В финкции DoReadDataSize мне непонятно вот это место
if ActualBytesRead <> - 1 then
Inc(TotalDataSizeBytesRead, ActualBytesRead);
мне кажется должно быть так
if ActualBytesRead <> - 1 then
Inc(TotalDataSizeBytesRead, dword(buf^));


 
V_Pavel   (2002-11-08 17:55) [25]

Digitman © Твой пример приемника тоже не примнмает маленькие пакеты после большого.


 
V_Pavel   (2002-11-09 07:53) [26]

Дело тут не в приемнике а в передатчике который описал Digitman ©. Он после передачи длинного пакета подвисает последующие пакеты становятся в очередь но не передаются. Немогу понять в чем тут дело.


 
V_Pavel   (2002-11-10 06:25) [27]

После передачи большого пакета перестает реботать вот этот кусочек(выделенный жирным) кода в обработчике OnClientWrite()
if Assigned(Stream) and Socket.SendStream(Stream) then
Socket.Data := nil;
Вчем тут дело?



 
Digitman   (2002-11-10 08:13) [28]


> мне кажется должно быть так
> if ActualBytesRead <> - 1 then
> Inc(TotalDataSizeBytesRead, dword(buf^));


Это почему же ? Прокомментируй ход свей мысли.

> перестает реботать вот этот кусочек(выделенный жирным) кода
> в обработчике OnClientWrite()
> if Assigned(Stream) and Socket.SendStream(Stream) then
> Socket.Data := nil;


Что значит "перестает работать" ?


 
V_Pavel   (2002-11-10 12:54) [29]

да первое это я конечно глупость сморозил не до конца разобрался
а вот на счет Socket.SendStream(Stream) при посылке после большого пакета маленького выдает false.


 
Digitman   (2002-11-10 13:06) [30]

>>при посылке после большого пакета маленького выдает false

Ну и что ? False - всего лишь признак того, что полное содержимое потока не может в данный момент поставлено в очередь гнезда на передачу. Как только очередь освободится, возникнет очер.событие OnWrite(), очер.порция из потока будет считана из потока и поставлена в очередь, и , если поток не полностью вычерпан, снова результатом будет False ... и так до полного исчерпания потока... как только поток "кусками" будет полностью вычерпан, результатом будет True, а объект-поток автоматически уничтожен


 
Digitman   (2002-11-10 13:33) [31]

Вот что при этом происходит :

function TCustomWinSocket.SendStreamPiece: Boolean;
var
Buffer: array[0..4095] of Byte;
StartPos: Integer;
AmountInBuf: Integer;
AmountSent: Integer;
ErrorCode: Integer;

procedure DropStream;
begin
if FDropAfterSend then Disconnect(FSocket);
FDropAfterSend := False;
FSendStream.Free;
FSendStream := nil;
end;

begin
Lock;
try
Result := False;
if FSendStream <> nil then
begin
if (FSocket = INVALID_SOCKET) or (not FConnected) then exit;
while True do
begin
StartPos := FSendStream.Position;
AmountInBuf := FSendStream.Read(Buffer, SizeOf(Buffer));
if AmountInBuf > 0 then
begin
AmountSent := send(FSocket, Buffer, AmountInBuf, 0);
if AmountSent = SOCKET_ERROR then
begin
ErrorCode := WSAGetLastError;
if ErrorCode <> WSAEWOULDBLOCK then
begin
Error(Self, eeSend, ErrorCode);
Disconnect(FSocket);
DropStream;
if FAsyncStyles <> [] then Abort;
Break;
end else
begin
FSendStream.Position := StartPos;
Break;
end;
end else if AmountInBuf > AmountSent then
FSendStream.Position := StartPos + AmountSent
else if FSendStream.Position = FSendStream.Size then
begin
DropStream;
Break;
end;
end else
begin
DropStream;
Break;
end;
end;
Result := True;
end;
finally
Unlock;
end;
end;

function TCustomWinSocket.SendStream(AStream: TStream): Boolean;
begin
Result := False;
if FSendStream = nil then
begin
FSendStream := AStream;
Result := SendStreamPiece;
end;
end;


 
V_Pavel   (2002-11-10 17:17) [32]

Я это все прекрасно понимаю но из за того что SendStream выдает False данные копятся в буфере и не передаются. Я передаю пакет длиной 100 кил. Он передается но если следом передавать к примеру 2 пакета по 7 байт. Вот они остаются в очереди. Я так понимаю что при передаче большого пакета Socket блокируется пока его не передаст. Ток вот не удобнее ли здесь использовать SendBuff и передавать это все кусками.


 
Digitman   (2002-11-10 18:02) [33]

при чем здесь SendBuf() и иже с ними ?
Я тебе для чего привел фрагмент кода от Борланда ? Чтобы ты ВНИК в него и не делал "отфонарных" умозаключений ! Данные потока передаются именно поблочно ! Или , как ты там говоришь, - "кусками")...

Лучше скажи, сколько раз возникает событие OnWrite() при посылке, скажем, фрагмента в 100кб и следом за ним - 7б


 
V_Pavel   (2002-11-11 06:28) [34]

Событие OnClientWrite() возникает в данном случае 2 раза первый раз когда передаетя большой пакет второй раз когда маленький но прередача маленького не осушествляется.


 
Digitman   (2002-11-11 08:26) [35]


> первый раз когда передаетя большой пакет


Быть того не может ! Самое первое событие OnWrite(), ДАЖЕ ЕСЛИ НИЧЕГО НЕ ПЕРЕДАЕТСЯ, должно возникать как минимум однократно. Это - извещение Winsock о готовности буфера передачи к записи в него блока потенциально передаваемых данных.

Каков полный объем переданных и принятых данных ? Я не спрашиваю, сколько раз возникало событие OnRead() у приемника - именно СКОЛЬКО БАЙТ всего получил приемник в результате передачи в общей сложности, например, 100 + 7 = 107кб ?


 
V_Pavel   (2002-11-11 11:36) [36]

На счет OnWrite()ты прав. Приемник получает 100 кил. А вот если передавать маленький пакет после того как большой был принят приемником то все работает.


 
Digitman   (2002-11-11 12:35) [37]


//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
Application.ProcessMessages // !!!!!!!!!!!!!!!!
Stream := Socket.Data;
if not Assigned(Stream) then
Stream := TMemoryStream.Create;
CurStreamReadPos := Stream.Position; //тек.позиция считывания из потока
Stream.Position := Stream.Size; //в конец потока
Stream.Write(...то что нужно передать...); //в хвост потока - новые данные
Stream.Position := CurStreamReadPos; //восстановление тек.позиции
if not Assigned(Socket.Data) and not Socket.Connections[index].SendStream(Stream) then
begin
Socket.Data := Stream;
Процедура_обработчика_OnClientWrite(ServerSocket, Socket);
end





 
V_Pavel   (2002-11-11 19:02) [38]

На LocalHost-е работает если разношу клиент и сервер по разным машинам ситуация повторяется.


 
Digitman   (2002-11-12 08:57) [39]

давай-ка еще раз вникни и посмотри, что не так, как ожидается


//тело обработчика OnClientWrite()
var Stream: TMemoryStream; //лок.переменная
...
Stream := TMemoryStream(Socket.Data);
// если ссылка на экземпляр исх.потока ассоциирована с гнездом
if Assigned(Stream)
// и в момент нижеследующего вызова ВСЕ содержимое потока
// успешно поставлено в очередь на передачу
and Socket.SendStream(Stream) then
// то экз-р исх.потока будет автоматически уничтожен
// в private-методе TCustomWinSocket.SendStreamPiece (DropStream)
// и ассоциация с экз-ром разорвана, чтобы известить внешний код
// о том, что экз-р больше не существует
Socket.Data := nil;


//в момент необходимости передачи данных клиенту
var Stream: TMemoryStream; //лок.переменная
var CurStreamReadPos: Integer; //лок.переменная
...
// первым делом даем возможность системе обработать тек.события, в т.ч. - OnWrite(), если оно возникнет в этот момент
//а если возникнет, то в его обработчике в случае успеха
// поток будет уничтожен, а ассоциация разорвана
Application.ProcessMessages;

// считываем состояние ассоциации
// изначально в OnConnect() она сброшена в nil
Stream := Socket.Data;

// если на этот момент еще ничто не передавалось
// или ранее осуществленные попытки передачи завершились успешно
// и предудущий экз-р потока уже не существует (уничтожен в DropStream)
if not Assigned(Stream) then

// создадим новый экз-р потока
Stream := TMemoryStream.Create;

// фиксируем тек.позицию считывания из потока
// ибо не делаем никаких предположений о том,
// новый это поток или уже существующий и ассоциированный с гнездом
CurStreamReadPos := Stream.Position;

//смещаем тек.позицию в конец потока
Stream.Position := Stream.Size;

//в хвост потока записываем то, что необходимо передать
Stream.Write(...то что нужно передать...);

//восстанавливаем тек.позицию в потоке
// для того, чтобы метод SendStreamPiece() мог начать продолжить
// отложенную передачу именно с того места, с которого при его предыд.вызове была неуспешной попытка передачи очер.блока
Stream.Position := CurStreamReadPos;

//если ассоциации на дан.момент нет, т.е. экз-р потока вновь создан
if not Assigned(Socket.Data) then
begin

// фиксируем ассоциацию гнезда с новым экз-ром потока
Socket.Data := Stream;

// стартуем потытку передачи потока
Процедура_обработчика_OnClientWrite(ServerSocket, Socket.Connections[index]);
end
// иначе ничего делать не надо -
// ассоциация есть, значит, ранее уже тем или иным образом
// OnWrite() вызывалась и на сей момент ассоциированный поток
// находится в стадии отложенной передачи;
// для продолжения/завершения отложенной передачи
// полагаемся на событие OnWrite(), которое будет вызвано
// автоматически, как только буфер гнезда освободится;
// здесь, в принципе, можно еще раз вызвать Application.ProcessMessages;




 
V_Pavel   (2002-11-12 12:15) [40]

Вроде все так но на самом деле чтото не так. У меня вот какое предположение. Вызвали мы метод SendStream он вернул True но на самом деле физически часть пакета еще находится на сервере. И скорее всего пока они не передадутся сокет заблокирован. Если это так то отсюда вопрос как узнать передан пакет или нет.


 
Digitman   (2002-11-12 12:38) [41]


> но на самом деле физически часть пакета еще находится на
> сервере


На стороне передатчика - так будет вернее в общем случае.

А какое тебе дело до "физики" ?

Если send-метод вернул True, это уже не твоя забота, как и когда все это "физически" будет доставлено приемнику. Все ! О факте достоверной физической доставки Winsock не обязан извещать тебя. Ибо низкоуровневый IP-транспорт - механизм достаточно сложный и доставка в реалии выглядит вовсе не так, как это выглядит для прикладной программы

Если же send-метод вернул False, то это означает только одно : в данный момент Winsock не может принять данные для передачи и, как только будет свободен позднее, известит тебя об этом в событии OnWrite().


> как узнать передан пакет или нет.


Принимающая сторона при необходимости может, в свою очередь, послать подтверждение по факту приема сообщения


 
V_Pavel   (2002-11-12 13:15) [42]

А каким образом Winsock известит меня что свободен и готов к следующей передаче т е как я могу отследить этот момент.

P.S. Может я конечно задаю глупые вопросы но мне очень хочется разобраться.




 
Erik   (2002-11-12 13:33) [43]

Да заеяли вы обсуждение, какбудто космический корабль запускаете!
Digitman будь проще и народ к тебе потянеися :)
V_Pavel ты идеалогию измени, прописывай в каждый пакет заголовок в котором содержится размер. И использй Indy+UDP блокирующей режим невызывает трудностей при програмировании. Правда если у тебя передача вне локалтной сети то UDP следует пользоватся с осторожностью. Физический размер пакета в UDP может достигать 64К


 
Digitman   (2002-11-12 13:39) [44]

Вот на то и существует событие OnWrite() !


Оно возбуждается как минимум 1 раз - сразу следом за событием OnConnect()

Кр.того, в неблок.режиме событие OnWrite() возбуждается всякий раз, когда Winsock не в состоянии в момент предыдущего обращения прикладной задачи к send-ф-ции принять к передаче указанный блок данных указанного размера.
Иными словами, если режим - неблокирующий и попытка вызова ф-ции send() вернула результатом значение SOCKET_ERROR с кодом отказа WSAGetLastError() = WSAEWOULDBLOCK (10035), то тем самым Winsock говорит : я сейчас не в состоянии принять к исполнению то, что просишь передать, я занята передачей того, что ты от меня потребовал ранее, подожди, я сообщу о готовности как только буду свободна событием FD_WRITE


 
Digitman   (2002-11-12 13:43) [45]

>Erik

Вот в твоих никчемных комментариях, сударь, в данном случае я нуждаюсь меньше всего.


 
Erik   (2002-11-12 16:48) [46]

Осмелюсь заметить сударь, что дополнения нетакие уж никчемные! Я сделал сервер с клиентом для сетевой работы с устройством висящем на com порту. И Indy у UDP прекрасно для этого подошол. Следовательно могу рекомендовать то, что проверил лично!


 
Digitman   (2002-11-12 17:00) [47]

>Erik

Да на здоровье. Сделал и сделал. Флаг тебе в руки. Но это отнюдь не дает тебе повода для указаний, быть мне "проще" или "сложней".
Касаемо сабжа, автор хочет понять внутреннюю "кухню" гнезд Беркли, и я всего лишь стремлюсь помочь ему в этом. Уясни для себя это и комментарии свои, не относящиеся к теме, впредь выноси в отдельные ветки. Будь уж так любезен.


 
V_Pavel   (2002-11-13 08:21) [48]

>Erik
Ну раз все так круто работает приведи пример приемника и передатчика пакетов.


 
V_Pavel   (2002-11-13 08:40) [49]

> Digitman ©
Я тут набросал проект на основе твоих рекомендаций, может посмотришь что там не так почему он не работает как надо.


 
Digitman   (2002-11-13 08:43) [50]

Бросай сюда. Лишнего не надо, только - процедуры передачи и приема


 
V_Pavel   (2002-11-13 08:55) [51]

> Digitman ©
Да вот наверно лучше я тебе на мыло вышлю. т.к. процедуры приема и передачи пакетана на 99% идентичны описанным тобой.


 
V_Pavel   (2002-11-13 12:00) [52]

> Digitman ©
Я послал тебе на мыло свой проект. Посмотри пожалуста почему он не работает как надо.


 
Digitman   (2002-11-13 12:18) [53]

Ок, посмотрю.

P.S. Мыло-то откуда взял ? Из старых "запасов", очевидно ? Анкетка-то моя "рухнула" при последнем известном катаклизме на сайте, сам даже добраться не могу, на себя, любимого, посмотреть-полюбоваться)


 
Erik   (2002-11-13 12:33) [54]

V_Pavel привожу примеры приема отправки пакетов для UDP.
В Indy есть только блокирующй режим, поэтому надо посылпть пакеты в нутри треда. Если коечно висеть не хочется.
Передача с клиента и получения подтверждения:
procedure TDecoder.SendUDP(Index: Byte);
Var PackCmd: TPackCmd;
PackConf: TPackConf;
Error, IP: String;
Size: Integer;
Begin
if GenParams(Index, IP, PackCmd) then begin
Error := "";

IdUDPClient.SendBuffer(IP, WPort, PackCmd,SizeOf(PackCmd));
try
Size := IdUDPClient.ReceiveBuffer(PackConf,SizeOf(PackConf));
if Size = SizeOf(PackConf) then begin
if PackConf.Id <> PackCmd.Id then Error := "Packet id not eiqual";
end else Error := "Not recive packet";
except
on E: Exception do Error := E.Message;
end;
end else Error := "Not gen params";

Notification(Index,PackConf, Error);
end;

Получение на сервере:
IdUDPServer := TIdUDPServer.Create(nil);
IdUDPServer.OnUDPRead := UDPServerUDPRead;
procedure TRealEvent.UDPServerUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
begin
Size := AData.Size;
Case Size of
SizeOf(Params): AData.Read(Params, Size);
....
end;

Помоему все очень просто. И примеры для Indy просто сказка. В них возможно есть готовое решение.


 
savva   (2002-11-13 15:30) [55]

> Digitman © (13.11.02 12:18)
> P.S. Мыло-то откуда взял ?
а мышку на ник свой наведи:))


 
Digitman   (2002-11-13 15:54) [56]

>savva

А, ну да ...точно)... я уж и забыл)...

Любопытно вот, а какого, пардон, хрена мыло отдельно от анкетки хранится в базе ? Вот хоть убей - не пойму сей логики)... imho, дурь ... или вообще никакой сквозной логики ... или отупел я совсем)))







 
savva   (2002-11-13 16:34) [57]

> Digitman © (13.11.02 15:54)
наврядли это база, скорее всего это куки - они то и подставляют твое мылов поле e-mail когда ответ пишешь.. уберешь оттуда мыло - и не будет его напротив ника - как у меня...:-)))


 
Digitman   (2002-11-13 16:49) [58]

>savva

Может, и куки) ... не задумывался
А вот то, что анкетная база рухнула - это по-любому печально


 
savva   (2002-11-13 17:01) [59]

она рухнуть то рухнула, но теперь все исправили, можно заново зарегистрироваться (если конечно не влом:)). я тоже бы в списке "тех кто уже не с нами", а сейчас "воскрес" Ж)


 
Digitman   (2002-11-13 17:40) [60]

>savva

Да ну и хрен с ней, с анкетой ... я уж тут за пару лет "нарисовался" своими "перлами" - без всякой анкеты понятно, что говорить со мной "нормально" невозможно в принципе))))))))



Страницы: 1 2 вся ветка

Форум: "Сети";
Текущий архив: 2003.01.13;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.64 MB
Время: 0.008 c
3-36928
Antah
2002-12-17 13:56
2003.01.13
Проблема с запросом SELECT FROM WHERE LIKE


7-37395
Senator
2002-11-01 12:57
2003.01.13
скорость CD-Rom


14-37354
J_S
2002-12-24 12:58
2003.01.13
dbExpress


4-37458
Демонов Е.В.
2002-11-26 05:36
2003.01.13
Вопрос о адресном пространстве.


4-37455
Maksss
2002-11-18 03:39
2003.01.13
Создание контролов





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский