zoukankan      html  css  js  c++  java
  • 基于IOCP的高速文件传输代码

    //服务端:

    const
      //transmit用的参数
      TF_USE_KERNEL_APC     = $20;
      //命令类型
      CMD_CapScreen             = 2000;
      CMD_CapVideo              = 2001;
      CMD_CapAudio              = 2002;
      CMD_GetSystemInfo         = 2003;
      CMD_TransmitFiles         = 2004;
      
    //通用数据传输包体封装
    type
      //每个完整数据的头描述
      TPacketHeader =  packed record
         PacketCMD    : Word;   //包类型
         DataLength   : Word;   //包体长度
         IsCompressed : Boolean//包体是否为压缩数据
      end;
      TBytes = array [0..65535of Byte;
      TPacketBody = packed record
         Data : TBytes;
      end;
      //完整的数据包
      TPacketInfo = packed record
        Header : TPacketHeader;
        Body   : TPacketBody;
      end;
      //文件发送包
      TFileSendPacket = packed record
        FileName : array [0..127of Char;
        FileSize : LongWord;
        StartWritePositon : LongWord;
        hFile : THandle;
      end;
    function TServerClientSocket.TransFile(FileName: string;StartWritePositon:LongWord): Boolean;
    var
      hFile : THandle;
      NumberOfByteSend : LongWord;
      Block:PBlock;
      PacketInfo: TPacketInfo;
      FileSendPacket : TFileSendPacket;
      AFileName : string[128];
      TransmitFileBuffers : TTransmitFileBuffers;
    begin
        if not FileExists(FileName) then
        begin
          Result := False;
          Exit;
        end;
        
        hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 00);
        //如果文件打开错误,则退出
        if hFile = INVALID_HANDLE_VALUE then
        begin
          Result := False;
          Closehandle(hFile);
          Exit;
        end;
        //得到需要传输的字节数
        NumberOfByteSend := windows.GetFileSize(hFile, nil) - StartWritePositon;
        if NumberOfByteSend <= 0 then
        begin
          Closehandle(hFile);
          Exit;
        end;
        Block := AllocBlock;
        Block.Data.Event := seFileSend;
        Block.Data.Overlapped.Offset := StartWritePositon;
        AFileName := ExtractFileName(FileName);
        FillChar(PacketInfo,SizeOf(TPacketInfo),0);
        FillChar(FileSendPacket,SizeOf(TFileSendPacket),0);
        Move(AFileName[1],FileSendPacket.FileName,length(AFileName));
        FileSendPacket.FileSize := NumberOfByteSend;
        FileSendPacket.StartWritePositon := StartWritePositon;
        FileSendPacket.hFile := hFile;
        PacketInfo.Header.PacketCMD := CMD_TransmitFiles;
        PacketInfo.Header.DataLength := Sizeof(TFileSendPacket);
        PacketInfo.Header.IsCompressed := False;
        Move(FileSendPacket,PacketInfo.Body.Data,SizeOf(TFileSendPacket));
        Move(PacketInfo,Block^.Data.Buffer,SizeOf(TPacketHeader) + SizeOf(TFileSendPacket));
        //传输文件前发送的包
        TransmitFileBuffers.Head := @Block^.Data.Buffer[0];
        TransmitFileBuffers.HeadLength := SizeOf(TPacketHeader) + SizeOf(TFileSendPacket);
        //传输文件完毕后发送的包
        TransmitFileBuffers.Tail := nil;
        TransmitFileBuffers.TailLength := 0;
        LogMsg('开始发送文件:' + FileName + ' Size=' + IntToStr(NumberOfByteSend));
        //发送命令,并将文件名、继传点、需要传输的大小传递过去
        if not TransmitFile(SocketHandle, hFile, NumberOfByteSend, MAX_BUFSIZE,
          @Block^.Data.Overlapped, @TransmitFileBuffers, TF_USE_KERNEL_APC) then
        begin
          if GetLastError <> ERROR_IO_PENDING then
          begin
            Result := False;
            Exit;
          end;
        end;
        Result := True;
    end;
    //如果发送完毕,可以接收到重叠IO的返回结果
        case Block^.Data.Event of
          seFileSend:
          begin
            Block.IsUse := False;
            Move(Block.Data.Buffer,PacketInfo,SizeOf(TPacketHeader) + SizeOf(TFileSendPacket));
            if PacketInfo.Header.PacketCMD = CMD_TransmitFiles then
            begin
               FillChar(FileSendPacket,SizeOf(TFileSendPacket),0);
               Move(PacketInfo.body.data,FileSendPacket,SizeOf(TFileSendPacket));
               Closehandle(FileSendPacket.hFile); //发送完毕,关闭文件句柄
            end;
            LogMsg('文件:' + StrPas(FileSendPacket.FileName) + '  发送完毕!');
            if not PrepareRecv() then Result := RESPONSE_FAIL;       
          end;
          seRead: 。。。。。。。
      
    //客户端:
    procedure TrecvThread.Execute;
    var PacketInfo : TPacketInfo;
        str: string;
        FileSendPacket:TFileSendPacket;
        FileStream:TFileStream;
        FileName :string;
        RecBuf:array[0..1023of Char;
        RemainByts,RecvedBytes:Integer;
    begin
      while (not self.Terminated ) DO
      begin
        cs.CheckForDisconnect(False);
         if cs.ClosedGracefully then
         begin
            Fmm.Lines.Add('链路断开!');
            self.Terminate;
         end;
         cs.ReadBuffer(PacketInfo.Header,SizeOf(TPacketHeader));
         cs.ReadBuffer(PacketInfo.Body.Data, PacketInfo.Header.DataLength);
         if PacketInfo.Header.PacketCMD = CMD_TransmitFiles then
         begin
           Move(PacketInfo.Body.Data,FileSendPacket,PacketInfo.Header.DataLength);
           FileName := StrPas(FileSendPacket.FileName);
           try
             FileStream := TFileStream.Create('C:'+ FileName, fmCreate or fmOpenWrite);
             Fmm.Lines.Add('接收:' + FileName + ' Size=' + IntToStr(FileSendPacket.FileSize));
             RecvedBytes := 0;
             while (RecvedBytes < FileSendPacket.FileSize) do
             begin
               if FileSendPacket.FileSize <= 1024 then
               begin
                 cs.ReadBuffer(RecBuf,FileSendPacket.FileSize);
                 RecvedBytes := FileSendPacket.FileSize;
                 FileStream.WriteBuffer(RecBuf,RecvedBytes);
                 Break;
               end else begin
                 cs.ReadBuffer(RecBuf,1024);
                 RecvedBytes := RecvedBytes + 1024;
                 FileStream.WriteBuffer(RecBuf,1024);
                 RemainByts := FileSendPacket.FileSize - RecvedBytes;
                 if RemainByts <= 1024 then
                 begin
                   cs.ReadBuffer(RecBuf,RemainByts);
                   RecvedBytes := RecvedBytes + RemainByts;
                   FileStream.WriteBuffer(RecBuf,RemainByts);
                   Break;
                 end;
               end;
             end;
           finally
              FileStream.Free;
           end;
         end;
      end;
    end;

    http://www.delphi6.com/thread-554.htm

  • 相关阅读:
    17. 文件查找
    18. 后台进程
    16. Linux 文件目录权限
    15. SSH 远程
    14. 用户管理
    Emacs Python 自动补全--Elpy
    C++ 程序在运行时不显示dos界面
    OpenCV设置摄像头分辨率及全屏显示
    #error : Xiron Platform Abstraction Layer
    Win10 下Cmake编译配置 Opencv3.1 + Cuda7.5 + VS2013
  • 原文地址:https://www.cnblogs.com/findumars/p/7207696.html
Copyright © 2011-2022 走看看