Текущий архив: 2002.12.12;
Скачать: CL | DM;
Вниз
Опять про ServerSocket@ClientSocket Найти похожие ветки
← →
Hirara © (2002-10-09 00:02) [0]При работе с TMemoryStream большие файлы не передаются, примерно до 8 кБ, в чом трабл? Вот коды :
Прием Файла:
procedure TForm1.ServerSocket2ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
VAR s,s1 : String;
Data : TMemoryStream;
begin
S:=Socket.ReceiveText;
If Not Recieving Then
Begin
S1:=Copy(s,1,Pos(#1,s)-1);
Delete(s,1,Pos(#1,s));
DataSize:=StrToInt(S1);
Data:=TMemoryStream.Create;
Recieving := True;
End;
Try
Data.WriteBuffer(S[1],Length(s));
Data.SaveToFile("c:\11111");
if Data.Size = DataSize then
begin
Data.Position:= 0;
Data.Free;
Recieving:= false;
End;
Except
// Data.Free;
End;
Отправка файла :
procedure TForm1.Button4Click(Sender: TObject);
var MyStream : TMemoryStream;
begin
MyStream := TMemoryStream.Create;
Try
MyStream.LoadFromFile(Edit4.Text);
MyStream.Position:=0;
ClientSocket2.Socket.SendText(IntToStr(MyStream.Size)+#1);
ClientSocket2.Socket.SendStream(MyStream);
Except
MyStream.Free;
End;
← →
Lex_! © (2002-10-09 08:44) [1]не в размере проблема, а в содержании файла, если в файле есть символы с кодом меньше 33 то не будет работать, так как некоторые коды принимаються как управляющиеся.. но может я и не прав...используй другие компоненты
← →
neodiX © (2002-10-15 14:13) [2]Дело в том что по дефолту компонент Тclientsocket передает пакеты величиной в 8 КБ. Т.е. если у тебя файл больше 8 кб, то вначале ты должен получить все данные, а потом создавать файл. В своем коде пиши так:
. . .
Try
Data.WriteBuffer(S[1],Length(s));
if Data.Size = DataSize then
begin
Data.Position:= 0;
Data.SaveToFile("c:\11111");
Data.Free;
Recieving:= false;
End;
Except
// Data.Free;
End;
. . .
← →
F1 (2002-10-17 13:09) [3]Пробовал частями, тогда все нормально, но после 32 килобайт передается какой-то мусор (32 байта). В чем проблема, так и не понял.
← →
Digitman © (2002-10-17 15:55) [4]На самом деле все достаточно просто.
Все , что нужно - почитать хэлп и посмотреть особености реализации метода SendStream() в исходниках.
← →
Bsl (2002-10-18 08:18) [5]Вообще портокол tcp/ip передает данные без каких-либо разделителей. Так что если ты пошлешь сразу второй файл, то он придет слитно с первым (или ты можешь задержку передачи принять за конец файла).
По этому поводу рекомендую все пересылаемые данные обрамлять своей служебной информацией (типа: назначение пакета, длинна и т.д.); при получении пытаться все это собрать.
Только так это и работает, особенно если нужно передавать какие-либо команды или пачки малых данных (разного размера).
← →
Digitman © (2002-10-18 09:22) [6]в дополнение к <Bsl (18.10.02 08:18)>
этот код дает (вызываемый в теле SendStream) наглядное представление о том, что в действительности происходит при передаче потока
function TCustomWinSocket.SendStreamPiece: Boolean;
var
Buffer: array[0..4095] of Byte; // 1/2 размера send-буфера передачи гнезда , по-умолчанию он = 8к
StartPos: Integer;
AmountInBuf: Integer; // всего данных в буфере потока
AmountSent: Integer; // достоверно помещено в send-буфер гнезда в рез-те очередной итерации цикла while true do
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)); // попытка прочитать из исх.потока очередные 4к (но не более)
if AmountInBuf > 0 then // если есть еще непереданные данные размером <= 4k
begin
AmountSent := send(FSocket, Buffer, AmountInBuf, 0); // попытка передачи в send-буфер гнезда очередного прочитанного из потока блока размером <= 4k
if AmountSent = SOCKET_ERROR then //если - отказ
begin
ErrorCode := WSAGetLastError; // получаем причину отказа
if ErrorCode <> WSAEWOULDBLOCK then //если отказ не связан с неблок.операцией
begin
Error(Self, eeSend, ErrorCode); // генерация исключения
Disconnect(FSocket); // разрыв вирт.петли коннекта
DropStream; // уничтожение потока
if FAsyncStyles <> [] then Abort; //фатальная ошибка - операция асинхронная, но по непонятным причинам ErrorCode <> WSAEWOULDBLOCK
Break;
end else // иначе - подождать и повторить передачу очер.блока потока размером в <= 4k (начиная с StartPos) позже, когда send-буфер гнезда освободится и сигналом об этом будет событие OnWrite()
begin
FSendStream.Position := StartPos; // восстановим исх.позицию очер.блока в потоке (ибо был smart-отказ), с которого можно повторить передачу потока при возникновении ближ.события OnWrite()
Break; // прервать цикл, снова войдем в него позже, вызвав SendStream (для того же потока) в событии OnWrite()
end;
end else if AmountInBuf > AmountSent then // очер.блок успешно передан, но исх.поток еще не вычерпан до конца
FSendStream.Position := StartPos + AmountSent // увеличиваем позицию в исх.потоке на величину, равную размеру успешно переданного блока
else if FSendStream.Position = FSendStream.Size then // готово ! весь исх.поток вычерпан и передан поблочно в sedn-буфер гнезда за одну или более итераций цикла в одном или более вызове SendStream
begin
DropStream; //уничтожаем поток
Break; //прерываем цикл
end;
end else
begin
DropStream; // то же самое
Break; //
end;
end;
Result := True;
end;
finally
Unlock;
end;
end;
Страницы: 1 вся ветка
Текущий архив: 2002.12.12;
Скачать: CL | DM;
Память: 0.49 MB
Время: 0.012 c