Форум: "Сети";
Текущий архив: 2004.10.03;
Скачать: [xml.tar.bz2];
ВнизПередача буфера большего чем ~270kb Найти похожие ветки
← →
Nikolay (2004-07-28 14:53) [0]Уважаемые мастера!
Я понимаю, что вопрос о передаче файла через сокеты уже всех в корень задолбал, но вот никак не могу решить задачу. Буфер отсылается/принимается только если его размер сравнительно небольшой. Код клиента (отсылает):
// clt: TTcpClient; BlockMode = bmBlocking
procedure TFormClient.btnSendFileClick(Sender: TObject);
var
data: TMemoryStream;
s: String;
begin
if dlgOpen.Execute then begin
data := TMemoryStream.Create;
data.LoadFromFile(dlgOpen.FileName);
SetLength(s, data.Size);
data.Position := 0;
data.Read(s[1], data.Size);
try
if clt.Connect then begin
clt.Sendln("file " + IntToStr(data.Size));
clt.Disconnect;
if clt.Connect then
clt.SendBuf(s[1], Length(s);
end;
finally
clt.Disconnect;
data.Free;
end;
end;
end;
Сервер, принимающая сторона:
// srv: TTcpServer; BlockMode = bmThreadBlocking
procedure TFormServer.srvAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
s: String;
data: TMemoryStream;
begin
if GetFile {индикатор приема} then begin
data := TMemoryStream.Create;
try
SetLength(s, FileSize);
// FileSize: integer; - узнается из строки "file XXXX"
// посылаемой перед отправкой файла
ClientSocket.ReceiveBuf(s[1], FileSize);
data.Size := Length(s);
data.Position := 0;
data.Write(s[1], Length(s));
data.SaveToFile("c:\test.tmp");
finally
data.Free;
GetFile := False;
FileSize := 0;
end;
end;
end;
На малых файлах работает. Большие не отправляются. Думаю загвоздка здесь (SendBuf() = -1):
-------
For non-blocking sockets, the data is sent to the WinSock DLL which has it"s own internal buffers. If the WinSock can accept additional data, SendBuf returns immediately with the number of bytes queued. If the WinSock internal buffer space is not able to accept the buffer being sent, SendBuf returns -1 and no data is queued at all. In this case, wait a bit for the WinSock to have a chance to send out already-queued data; then try again.
-------
Только как это обойти, я никак не могу понять... :(
Есть предложения?
← →
Digitman © (2004-07-28 15:01) [1]
> Думаю загвоздка здесь (SendBuf() = -1):
... и далее цитируешьь справку для НЕблокирующего режима !
хотя ранее в своем коде явно отмечаешь , что у тебя блокирующий режим
// clt: TTcpClient; BlockMode = bmBlocking
чему верить ?
← →
Nikolay (2004-07-28 19:26) [2]Упс, за замечание спасибо. Ну только тогда я вобще не въезжаю, почему SendBuf() возвращает -1 !?!
ps Верить тому, что сокеты работают в блок. режиме
← →
Rouse_ © (2004-07-28 22:56) [3]Это означает ошибку. Код ошибки смотри в WSAGetLastError
← →
Nikolay (2004-07-29 03:03) [4]WSAECONNRESET
(10054)
Connection reset by peer.
A existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, or the remote host used a "hard close" (see setsockopt for more information on the SO_LINGER option on the remote socket.)
---------
Метод постоянно возвращает это значение! Пробовал убратьclt.Disconnect
не помогло :(
По какой такой причине это происходит?
← →
Slym © (2004-07-29 04:26) [5]Херушки этот код будет работать....
ты че делаеш?...
Коннект
Отправляешь размер
ДИСКОННЕКТ!
Коннект
Отправляешь файл!
Глупо не правдя?
← →
Slym © (2004-07-29 04:29) [6]// clt: TTcpClient; BlockMode = bmBlocking
procedure TFormClient.btnSendFileClick(Sender: TObject);
var
data: TMemoryStream;
s: String;
begin
if dlgOpen.Execute then begin
data := TMemoryStream.Create;
data.LoadFromFile(dlgOpen.FileName);//это первая глупость! Зачем пямять под стреам и потом под строку?
SetLength(s, data.Size);
data.Position := 0;
data.Read(s[1], data.Size);
try
if clt.Connect then begin
clt.Sendln("file " + IntToStr(data.Size));
clt.Disconnect;//вторая глупость...
if clt.Connect then
clt.SendBuf(s[1], Length(s);
end;
finally
clt.Disconnect;
data.Free;
end;
end;
end;
← →
Slym © (2004-07-29 04:48) [7]
procedure TFormClient.btnSendFileClick(Sender: TObject);
var
data: TFileStream;
begin
if dlgOpen.Execute then begin
data := TFileStream.Create(dlgOpen.FileName,ReadOnly);
try
if clt.Connect then begin
clt.Sendln("file " + IntToStr(data.Size));
clt.SendStream(data);
end;
finally
clt.Disconnect;
data.Free;
end;
end;
Сервер, принимающая сторона:
procedure TFormServer.srvAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
s: String;
data: TMemoryStream;
begin
if GetFile {индикатор приема} then begin
data := TMemoryStream.Create;
try
s:=ClientSocket.Receiveln;
delete(s,1,5);//удаляем file_
data.Size := StrToInt(s);
data.Position := 0;
ClientSocket.ReceiveBuf(data.Memory^,data.Size,0);
data.SaveToFile("c:\test.tmp");
finally
data.Free;
GetFile := False;
FileSize := 0;
end;
end;
end;
← →
Nikolay (2004-07-29 07:35) [8]Интересно, а этот код проверян? Специально создал отдельный проект. Скопировал все как здесь. Опять же, отсылает только часть файла! (или весь файл, если он маленький). Может есть рабочий исходник для пересылки файлов с использованием tcp?
В любом случае, спасибо!
← →
Verg © (2004-07-29 08:16) [9]
> ClientSocket.ReceiveBuf(data.Memory^,data.Size,0);
И с чего вы взяли, что ReceiveBuf примет именно data.size байтов?
ReceiveBuf - это функция, возвращающая число реально принятых сокетом байтов.procedure TFormServer.srvAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
s: String;
data: TFileStream;
Buffer : array[0..4095] of byte;
DataSize : integer;
Res : integer;
begin
if GetFile {индикатор приема} then begin
data := TFileStream.Create("c:\test.tmp", fmCreate);
try
s:=ClientSocket.Receiveln;
delete(s,1,5);//удаляем file_
DataSize := StrToIntDef(s, 0);
while DataSize > 0 do
begin
Res := ClientSocket.ReceiveBuf(Buffer, min(DataSize, sizeof(Buffer)), 0);
// ф-ция min - модуль math
if Res < 0 then
raise Exception.Create(SysErrorMessage(WSAGetLastError)); // Ошибка
if Res = 0 then
break; // Неожиданный разрыв соединения
Dec(DataSize, Res);
Data.Write(Buffer, Res);
end;
finally
data.Free;
GetFile := False;
FileSize := 0;
end;
end;
end;
← →
Nikolay (2004-07-29 10:03) [10]Другое дело!
Большое спасибо, вроде разобрался!
← →
Digitman © (2004-07-29 10:10) [11]
> Verg © (29.07.04 08:16) [9]
а что, у TTcpServer нет события OnRead ? я просто не в курсе .. смотрю, ты в OnAccept все это хоз-во разместил, что в общем случае не есть корректно ... все-таки прием следует инициировать по факту FD_READ, а не FD_ACCEPT ...
← →
Verg © (2004-07-29 10:17) [12]
> [11] Digitman © (29.07.04 10:10)
Серверная компонента TTCPServer - это многопоточный серевер, обслуживающий входящие соединения блокирующими сокетами. Каждому соединению - отдельный поток. Кроме того, будучи linux - совместимым, он про FD_*** знать ничего не должен.
← →
Digitman © (2004-07-29 10:24) [13]
> Verg © (29.07.04 10:17) [12]
теперь все ясно, буду в курсе, спасибо
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2004.10.03;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.064 c