Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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
1-36152
SDS
2002-12-03 17:44
2002.12.12
Помогите!


3-36041
_toltec
2002-11-23 03:08
2002.12.12
Хранимая процедура


3-36058
Hlor
2002-11-25 01:08
2002.12.12
Прошу помочь! Как удалить текущую запись в таблице


14-36370
Basilio
2002-11-21 12:15
2002.12.12
Блин, где логин?


1-36092
Саррус
2002-12-01 01:23
2002.12.12
Многодокументный интерфейс