局域网文件传输 1个服务器 对应多个客户端(30左右);
怎么设计?大家有什么好的建议。
(目前我用TServersocket TclientSocket)实现了 但是速度很差、而且大文件(500多K)就会掉包。)
我分析了一下:
1、客户端发送得慢。TclientSocket的堆栈里面堆满来不急发的速度。所以丢失数据。
2、服务器端只是在ClientRead里面处理忙不过来。接受的堆栈堆满了速度。所以丢失
上面是我个人猜测。我也不知道他们堆栈有没有大小的。
我的代码:
客户端:Const SendLength=3000;
const SFilenameLength=40;
Const TotalSlength=3042;
//
Function FindFirst_FM:boolean;
var
   sr:TSearchRec;
   Attr:Integer;
   s:string;
begin
   result:=false;
   s:='CFileSend\*.jpg';
   Attr:=FaAnyFile;
   if  FindFirst(s,Attr,sr)=0 then
   begin
   FindClose(sr);
   SendFileName:=sr.name;
   form1.memo1.lines.add('Find File to Send:'+sr.name);
   result:=true;
   end;
end;
//启动线程后线程处理:
procedure TThreadClient.Execute;
var Fr,fw:TFileStream;
    size:int64;
    buf:array[1..TotalSlength] of char;
    SendTimes:integer;
    Pbuf:^CSendRecord;
    handle:thandle;
    realPos:int64;
    respart:integer;
begin
  while not Terminated do
  begin
     sleep(1000);
     if FindFirst_FM then  //检测文件
     begin
         //发文件
         //文件分割
         Fr:=TFileStream.Create('CFileSend\'+SendFileName,fmOPenRead);
         fr.Position:=0;
         size:=Fr.Size;
         sendTimes:=size div sendlength;
         respart:=size mod sendlength;
         while sendTimes>0 do
         begin
          form1.c1.Socket.
          realPos:=fr.Position;
          fillchar(buf,TotalSlength,0);
          buf[1]:='b';
          buf[2]:='b';
          move(sendfilename[1],buf[3],length(sendfilename));
          Fr.ReadBuffer(buf[SFilenameLength+3],SendLength);
          form1.c1.Socket.SendBuf(buf[1],TotalSlength);
          dec(sendtimes);
          sleep(300);
         end;
          if respart>0 then
          begin
             fillchar(buf,TotalSlength,0);
             buf[1]:='b';
             buf[2]:='b';
             move(sendfilename[1],buf[3],length(sendfilename));
             Fr.ReadBuffer(buf[SFilenameLength+3],respart);
             form1.c1.Socket.SendBuf(buf[1],TotalSlength);
          end;
         fr.Free;
         //备份文件
         copyfile(PAnsiChar('CFileSend\'+sendfilename),PAnsiChar('CFileSendHis\'+sendfilename),true);
         //删除文件
         deletefile('CFileSend\'+sendfilename);
     end;
  end;
end;
//服务器端
procedure TForm1.s1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var strrec:string;
    ip:string;
    cid:integer;
    size:int64;
    buf:array[1..TotalSLength] of char;
    fw:TFileStream;
    recfilename:string;
    OperateSign:string;
    handle:Thandle;
begin
fillchar(buf,TotalSLength,0);
ip:=socket.RemoteAddress;
socket.ReceiveBuf(buf[1],TotalSLength);
OperateSign:=buf[1]+buf[2];
if OperateSign='aa'then//aa表示客户端退出前发的信息。
begin
   deletecm(ip);
   memo1.Lines.Add(ip+': closed!');
end
else if OperateSign='bb'then  //bb表示传输的是文件
begin
  
   recfilename:=copy(buf,3,SendFLength+2);
   if fileexists('SFileRec\'+recfilename) then
   else
   begin
    handle:=filecreate('SFileRec\'+recfilename);
    fileclose(handle);
   end;
   fw:=TFileStream.Create('SFileRec\'+recfilename,fmOpenWrite);
   size:=fw.size;
   fw.position:=size;
   fw.WriteBuffer(buf[SendFLength+3],FSendLength);
   fw.Free;
end;

解决方案 »

  1.   

    局域网传输文件想提高速度,该用udp,自己做个简单的协议保证传输的可靠性就行了,应该很简单的。
      

  2.   

    服务器代码问题,你这里每接收到文件,都重新打开往里面写,肯定是非常慢的,在局域网内不存在数据发送不出去的问题,现在都是百兆网卡,理论速度是12M/S,我们一般写程序发送数据可以达到8M/S。procedure TForm1.s1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
    var strrec:string;
        ip:string;
        cid:integer;
        size:int64;
        buf:array[1..TotalSLength] of char;
        fw:TFileStream;
        recfilename:string;
        OperateSign:string;
        handle:Thandle;
    begin
    fillchar(buf,TotalSLength,0);
    ip:=socket.RemoteAddress;
    socket.ReceiveBuf(buf[1],TotalSLength);
    OperateSign:=buf[1]+buf[2];
    if OperateSign='aa'then//aa表示客户端退出前发的信息。
    begin
       deletecm(ip);
       memo1.Lines.Add(ip+': closed!');
    end
    else if OperateSign='bb'then  //bb表示传输的是文件
    begin
      
       recfilename:=copy(buf,3,SendFLength+2);
       if fileexists('SFileRec\'+recfilename) then
       else
       begin
        handle:=filecreate('SFileRec\'+recfilename);
        fileclose(handle);
       end;
       //你每次都是重新打开文件,效率非常低
       fw:=TFileStream.Create('SFileRec\'+recfilename,fmOpenWrite);
       size:=fw.size;
       fw.position:=size;
       fw.WriteBuffer(buf[SendFLength+3],FSendLength);
       fw.Free;
    end;
      

  3.   

    如果客户端个数很多,可以采用INDY的TIdTCPServer,并发性能会高很多。
      

  4.   

    SQLDebug_Fan 说的服务器反复打开文件的问题我也想过。我测试了一下在服务器开一个很大的buf
    然后先把读到的文件数据存在buf中 等传完了一次性写入文件。但是效果好像更慢了。我为什么服务器要做校验 、做返回。然后再让客户端再传 就是因为。不这个搞传过来的图片跟原来的图片相差太远了。
    局域网传输速度更定是很快的。但是肯定有速度丢失了。我猜测试 socket传输的buffer 太小了。
    好像一次读取最多才8000多个byte .只是猜测。因为我也不知道服务器socket控件 接受数据的区域到底有多打。
      

  5.   

    SQLDebug_Fan 说的服务器反复打开文件的问题我也想过。我测试了一下在服务器开一个很大的buf
    然后先把读到的文件数据存在buf中 等传完了一次性写入文件。但是效果好像更慢了。我为什么服务器要做校验 、做返回。然后再让客户端再传 就是因为。不这个搞传过来的图片跟原来的图片相差太远了。
    局域网传输速度更定是很快的。但是还是有数据丢失了。我猜测是 服务器socket接受信息的buffer 太小了。
    好像一次读取最多才8000多个byte .只是猜测。因为我也不知道服务器socket控件 接受数据的区域到底有多大
      

  6.   

    好像一次读取最多才8000多个byte .
    -----------------
    默认缓冲区是 8096
      

  7.   

    看一个很大的BUF,这样太占内存了,建议解决办法,用INDY的TIdTcpServer:由于TIdTcpServer是一个链接占一个线程,而且每个线程是分开的,因此你可以对每个线程创建一个类来管理,然后在OnExecute中不停的调用ReadBuffer来读取和处理数据,这样的好处是不用频繁的打开和关闭文件,而且性能比TServerSocket高。while not AThread.Terminated and AThread.Connection.Connected do
    begin
      AThread.ReadBuffer...;
      //处理数据
    end;TServerSocket是默认采用消息的,没有用多线程,因此客户端多的时候,性能非常成问题,我试了一下,把ServerType改成stThreadBlocking,TServerSocket的性能也不高。