用SOkET传送文件的问题请教————在线等待中!(100分)

  • 主题发起人 主题发起人 dfs
  • 开始时间 开始时间
D

dfs

Unregistered / Unconfirmed
GUEST, unregistred user!
部分代码如下:
try
GetMem(bufSend,iBYTEPERSEND+1);
if (fsSend.Position+1+iBYTEPERSEND) < fsSend.Size then
begin
ssize:=ssize+1;
sb.Panels[0].Text:='已发送'+inttostr(ssize)+'次';
sb.Panels[2].Text:=inttostr(trunc(fssend.Position*100/fssend.Size))+'%' ;
fsSend.Read(bufSend^,iBYTEPERSEND);
Socket.SendBuf(bufSend^,iBYTEPERSEND);
pb.Position:=trunc(fssend.Position*100/fssend.Size);
//
end//普通的发送,大小为iBYTEPERSEND
else begin
fsSend.Read(bufSend^,fsSend.Size-fsSend.Position-1);
Socket.SendBuf(bufSend^,fsSend.Size-fsSend.Position-1);
ssize:=ssize+1;
sb.Panels[0].Text:='已发送'+inttostr(ssize)+'次';
sb.Panels[2].Text:=inttostr(trunc(fssend.Position*100/fssend.Size))+'%' ;
pb.Position:=trunc(fssend.Position*100/fssend.Size);
over:=true;
ShowMessage('Send over!');
//fsSend.Free;
end;//最后一次发送,发送剩余的数据
finally
FreeMem(bufSend,iBYTEPERSEND+1);
end;{of try}

问题是最后一次发送完后,接受端没有受到数据(没有触发onread)事件。而前面那些传
送的数据都能够收到。
 
你处理的有问题,TCP应该不会丢包。
 
我每次调试都是这样,不是丢包的问题吧!
 
比如一个5k的文件应该发三次(每次两k),但接受到的都只有4k(只接受两次),发送端显示的是发送了3次,但第三次发送的数据没被接收到。
 
procedure TForm1.ClientSocket2Read(Sender: TObject;
Socket: TCustomWinSocket);
var len:integer;
temp:string;
begin
if stStatue=stgetFile then
begin
Len:=Socket.ReceiveLength;
Temp:=Socket.ReceiveText;
filem.Write(PChar(Temp)^,len); //filem是一个文件流
inc(allLen,len);
if allLen=getfilesize then //allLen是文件长度,你先传送过来
ShowMessage('文件接受完毕!');
end;

发送部分
const
MAX_LEN=2048;

var
iSen:integer; //iSen发送出去的长度
iSize:integer; //文件长度 最好是全局变量
buf:array[1..MAXLEN]of char;
senlen:integer; //每次应该发送的长度
ret:integer; //实际发送的文件长度
filen:TFileStream; //最好是全局变量

iSen:=0;
while iSen<iSize do
begin
FillChar(buf,MAX_LEN,0);
if iSize-iSen>MAX_LEN then senlen:=MAX_LEN
else senLen:=iSize-iSen;
filen.Position:=iSen;
filen.Read(buf,senLen);
ret:=ClientSocket1.Socket.SendBuf(buf,senLen);
inc(iSen,ret);
end;
 
原理一样的。我的问题是,为什么我这里最后那一点数据不能被接收,而前面那些却可以。的
 
:)原理不一样哦,你仔细看我的代码。
关键的细节不一样啊
 
你没有检查Socket.SendBuf的返回值。
 
为什么最后一次发送的数据会有问题呢?
 
你的发送部分代码有错误,不是TCP的问题,
 
fsSend.Read(bufSend^,fsSend.Size-fsSend.Position-1);
Socket.SendBuf(bufSend^,fsSend.Size-fsSend.Position-1);
上面是最后一次发送
fsSend.Read(bufSend^,iBYTEPERSEND);
Socket.SendBuf(bufSend^,iBYTEPERSEND);
上面是普通发送
区别只在发送的长度不同,为什么有错呢?

 
我真怀疑你认真看我的代码没有!
 
我已经解决了。不在发送端判断是否最后一次发送,而在接受端判断。
 
像你的那种发送办法在居于网上都不一定稳定,很有可能收不全数据,
到了internet上绝对是挂!
 
我在INTERNET上发送和接收289M的RAR文件一次通过。
 
对方如果开了很多IE再接受文件了?
你不检查sendbuf的返回值在internet上出问题的可能性很大,尤其你是用异步模式,
我对你成功发送表示怀疑,如果有一方是猫或者双方都是用猫那几乎不用看,文件发
送用你上面的代码是不可能完成的。
 
我也来说两句,请各大侠指教
张大侠说得有道理,传输文件用异步模式的确不是好方法。应该转用block模式的。
从代码上讲张大侠的比较可靠:
ret:=ClientSocket1.Socket.SendBuf(buf,senLen);
inc(iSen,ret);
因为从应用层代码级提供重传机制,提高了可靠性
尽量把可靠性掌握在自己的代码里,这是大侠的风范

dfs的代码由tcp提供可靠的传输,用户不再理会:
fsSend.Read(bufSend^,fsSend.Size-fsSend.Position-1);
Socket.SendBuf(bufSend^,fsSend.Size-fsSend.Position-1);
ssize:=ssize+1;
使用和信赖协议和操作系统提供的方便,减短开发周期

问题只是tcp已经提供确认重传的机制,还需不需要额外的代码去确认他
我以前的做法是判断Sendbuf(buffer,length)是否返回length的长度,假如不相等就跳出返回。
纯粹是基于tcp的可靠性,假如tcp也重传失败,再由用户重传也很可能失败。

但是也要考虑所使用的Api、库函数和操作系统所提供的可靠性到底有多少。
哪到底有多少呢?大家来说说吧
 
TO spidertong:
谢谢支持,其实用异步也一样可以传输大文件,我用DELPHI的TServerSocket和
TClientSocket传输过10M的大文件(用猫,每秒才2K),用的是异步方式,环境是
两个猫之间传输,每个数据包大小4K,我做了很好的处理,一样没有出任何问题
, 文件运行成功(,一个EXE).,如果要说明这个问题,估计要写一个很大的帖子。
上面那段代码没写好,是很久以前我写的,很多细节没有处理好,比如没有对
sendbuf返回出错的处理,还有一次可以读入一个大块数据,比如100K文件,分次
发送.减少大量的文件I/O,提高效率.
 
异步传输时,发送代码应该在OnWrite事件里做,而且要检验Sendbuf的返回值,代码构架
类似这样:
type
TForm1=class(TForm)
private
fs: TFilestream; //要发送的文件
bytesSent: integer;
...
end;

TForm1.ClientSocket1Write(Sender: TObject;
Socket: TCustomWinSocket);
var
nBytesRead, nBytesSent: integer;
buf: array [0..4095] of byte;
begin
fs.position := BytesSent;
repeat
if fs.position = fs.size then begin
exit; //所有内容都发送完成了
end;
nBytesRead := fs.read(buf, 4096);
nBytesSent := socket.sendbuf(buf, nBytesRead);
inc(BytesSent, nBytesSent);
until nBytesRead <> nBytesSent;
//缓冲区里的数据没有全部发完,说明Socket缓冲区已经满了
//暂时发送这一些,等下次事件继续发
end;
 
SOCKET在连接中S端是INTERNET连接共享的主机时不能被C端连接,但反过来用C去连对方的S端却可以如何解决呢?
 
后退
顶部