socket接收文件的問題 ( 积分: 100 )

  • 主题发起人 主题发起人 takdick
  • 开始时间 开始时间
T

takdick

Unregistered / Unconfirmed
GUEST, unregistred user!
我想用socket接收文件,服務端已得到要接收文件的大小和儲存路徑,但接收文件內容的代碼不知該如何寫?我知道使用記錄類型會較方便,但想知道存不使用的情況下又該如何處理?謝謝.

客戶端
filesize:longint;
filename,shortname:string;
m,ms1:tmemorystream;
procedure TForm1.uploadClick(Sender: TObject);
begin
if opendialog1.Execute then
begin
filename:=opendialog1.FileName;
shortname:=ExtractFileName(filename);
ms1:=tmemorystream.Create;
ms1.Position:=0;
ms1.LoadFromFile(filename);
filesize:=ms1.Size;
if filesize >8388608 then
begin
application.MessageBox('文件>8M,無法上傳','提示');
ms1.Free;
exit;
end;
ss.Socket.Connections[0].SendText('send');
end;
end;
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
str:string;
begin
str:=socket.ReceiveText;
if str='size' then
Socket.SendText('size'+inttostr(filesize));
if str='name' then
Socket.SendText('name'+filename+'.bak');
if str='data' then
Socket.SendStream(ms1);
if str='okok' then
begin
ss.Close;
showmessage('file send success.');
end;
end;

服務端
procedure TForm1.cs2Read(Sender: TObject; Socket: TCustomWinSocket);
var
ms:tmemorystream;
len,filesize:longint;
str,filename,filepath,head,tail:string;
buffer:array [0..10000] of byte;
begin
str:=Socket.ReceiveText;
head:=copy(str,1,5);
tail:=copy(str,6,length(str)-5);

if head='send' then
begin
Socket.SendText('size');
end;
if head='size' then
begin
filesize:=strtoint(tail);
Socket.SendText('name');
end;
if head='name' then //已收到要接收文件的大小和儲存路徑
begin
filename:=tail;
Socket.SendText('data');
end;

len:=socket.ReceiveLength; //請問以下接收文件的代碼該如何寫?還要加些什麼才能正常接收文件?
socket.ReceiveBuf(buffer,len);
ms:=tmemorystream.Create;
......
......
......
ms.SaveToFile(filename);
Socket.SendText('okok');
cs.Close;
end;
end;
 
我想用socket接收文件,服務端已得到要接收文件的大小和儲存路徑,但接收文件內容的代碼不知該如何寫?我知道使用記錄類型會較方便,但想知道存不使用的情況下又該如何處理?謝謝.

客戶端
filesize:longint;
filename,shortname:string;
m,ms1:tmemorystream;
procedure TForm1.uploadClick(Sender: TObject);
begin
if opendialog1.Execute then
begin
filename:=opendialog1.FileName;
shortname:=ExtractFileName(filename);
ms1:=tmemorystream.Create;
ms1.Position:=0;
ms1.LoadFromFile(filename);
filesize:=ms1.Size;
if filesize >8388608 then
begin
application.MessageBox('文件>8M,無法上傳','提示');
ms1.Free;
exit;
end;
ss.Socket.Connections[0].SendText('send');
end;
end;
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
str:string;
begin
str:=socket.ReceiveText;
if str='size' then
Socket.SendText('size'+inttostr(filesize));
if str='name' then
Socket.SendText('name'+filename+'.bak');
if str='data' then
Socket.SendStream(ms1);
if str='okok' then
begin
ss.Close;
showmessage('file send success.');
end;
end;

服務端
procedure TForm1.cs2Read(Sender: TObject; Socket: TCustomWinSocket);
var
ms:tmemorystream;
len,filesize:longint;
str,filename,filepath,head,tail:string;
buffer:array [0..10000] of byte;
begin
str:=Socket.ReceiveText;
head:=copy(str,1,5);
tail:=copy(str,6,length(str)-5);

if head='send' then
begin
Socket.SendText('size');
end;
if head='size' then
begin
filesize:=strtoint(tail);
Socket.SendText('name');
end;
if head='name' then //已收到要接收文件的大小和儲存路徑
begin
filename:=tail;
Socket.SendText('data');
end;

len:=socket.ReceiveLength; //請問以下接收文件的代碼該如何寫?還要加些什麼才能正常接收文件?
socket.ReceiveBuf(buffer,len);
ms:=tmemorystream.Create;
......
......
......
ms.SaveToFile(filename);
Socket.SendText('okok');
cs.Close;
end;
end;
 
怎麼沒人答,很難嗎?
help...
 
因为socket每次接收的数据有一定限制的,也就是是分批送的,我记得以前有个一个什么参数不稳定,忘记了,就是你自己要每次判断收了多少了,比如说你自己设定的每次最大收100K,然后你每次都判断,当前收到的是不是小于100K,如果小于100K,说明整个都收完,否则还继续收,大概是这样,记不得很清楚了

下面的这几个例子可以参考
-------------------------转自网络
http://www.delphibbs.com/delphibbs/dispq.asp?LID=632808

http://www.delphibbs.com/delphibbs/dispq.asp?LID=156184

用TServerSocket和TClientSocket的sendstream方法好象一次最大只能发送
8k的数据,如果大于8k就会出错。Aloney的方法我在D4上试过,如果图片小的
话没问题,大于8K的话就什么也收不到。

我采用拼接的方法实现了任意大小文件的传送(还是有些限制的,下面我将要说
明),以下程序在D4上调试通过:

Client端:(发方)
private
{ Private declarations }
stream : TMemoryStream;
size,count : integer; //定义全局变量

procedure TForm1.Button2Click(Sender: TObject);
begin
stream := TMemoryStream.Create; //流初始化
if OpenDialog1.Execute then
begin
stream.LoadFromFile(OpenDialog1.FileName);
size := stream.Size;
count := 0; //记录位置
ClientSocket1.Socket.SendText(inttostr(size)); //发送文件大小
end;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
rcvtxt : string;
buf : array [1..8192] of char;
left : integer; //剩余的字节数
begin
rcvtxt := Socket.ReceiveText;
left := size - count; //剩余的字节数
if AnsiPos('go',rcvtxt)=1 then //收方响应了则发送一块
begin
if sizeof(buf)<left then
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
end;
end;
end;



Server端:(收方)
private
{ Private declarations }
Tof : file;
size,count :integer;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..8192] of char;
rcvtxt : string;
left,len : integer;
begin
len := Socket.ReceiveLength;
if len<10 then //若数据长度少于10位则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
if SaveDialog1.Execute then
begin
AssignFile(ToF, SaveDialog1.FileName);
Rewrite(ToF, 1);
end;
Socket.SendText('go'); //创立文件后发送一个响应
end
else
begin
left := size - count; //计算剩余字节数
if sizeof(buf)<left then //满一块的则写一块,发送响应
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else //不满一块则只写剩余的,不用响应
begin
Socket.ReceiveBuf(buf,left);
BlockWrite(Tof,buf,left);
CloseFile(Tof);
end;
end;
end;

由于我的控制条件是用接收的数据长度来判断是否是文件流,对于长度小于10
bytes或长度模8192小于10的文件并不适用,但只要改变一下这个条件则可以
应用于大多数情况了
 

Similar threads

I
回复
0
查看
832
import
I
I
回复
0
查看
695
import
I
I
回复
0
查看
415
import
I
I
回复
0
查看
539
import
I
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部