二、delphi 开发的基于win socket文件传输系统(支持超4G文件,断点续传,多线程同时能传输100个文件以上,支持文件夹压缩传输)客户端

delphi 自带的TIdFtpServer和TIdFtpClient组件,在实际应用中发现,只能单线程传输较小的文件。有很大局限性。决定自己写一个文件传输系统。该传输系统经测试,可以同时传输100个文件以上,超过4G大小的文件,支持断点续传。同时支持对文件夹的压缩传输。基本满足业务的要求。现在把服务器端和客户端代码粘贴如下:

一、客户端

1、传输单元

unit uTransFileClient;

interface
uses windows,graphics,classes,zip,uSocket,uStr,uConfig;
const
  MAXPATH=260;
  MAXBUF=8192;
  CMD_FILE_LIST=4001;//列举目录;传递绝对路径;
  CMD_FILE_TRANS=4002;//文件传输
  CMD_FILE_DEL=4003;//删除文件

  wm_user=$0400;
  wm_TransData=wm_user+100+1;
type

  TAPIFlag=(Fstart,Frecv,Fsend,Fend);
  TThreadType=(FListFile,FTransFile);

  pTransFilesInfo=^stTransFilesInfo;
  stTransFilesInfo=packed record
    server:stSvrAddr;
    clientFile:array[0..MAX_PATH-1] of ansiChar;
    serverFile:array[0..MAX_PATH-1] of ansiChar;
    bUpLoad:bool;
    bFolder:bool;
    bCompleteDel:bool;
    aAPI:TAPIFlag;
    transed:cardinal;
    FileSize:cardinal;
    threadId:integer;
  end;
  pRequestFileInfo=^stRequestFileInfo;
  stRequestFileInfo=packed record
    fileName:array[0..MAX_PATH-1] of ansiChar;
    bUpLoad:bool;
  end;//
  pRecvData=^stRecvData;
  stRecvData=packed record
    server:stSvrAddr;
    data:pointer;
    dataSize:integer;
  end;
  pListFile=^stListFile;
  stListFile=packed record
    server:stSvrAddr;
    filename:array[0..MAX_PATH-1] of ansiChar;
    data:pointer;
    dataSize:integer;
  end;

function TransFilesClientThread(pTransFilesPara:pointer):BOOL;stdcall;
function TransFileClientThread(pTransFilePara:pointer):bool;stdcall;
procedure ProcessTransFile(const LocalFilename,RemoteFilename:ansiString;bUpload:boolean);overload;
procedure ProcessTransFile(const LocalFilename,RemoteFilename:ansiString;bUpload:boolean;threadId:integer);overload;
procedure initAddr();
procedure uploadFile(const LocalFilename,RemoteFilename:ansiString);
procedure downloadFile(const LocalFilename,RemoteFilename:ansiString);overload;
procedure downloadFile(const LocalFilename,RemoteFilename:ansiString;threadId:integer);overload;
function ListFileThread():bool;stdcall;
procedure ProcessListFile();
var
  DataSvrAddr:stSvrAddr;
  gFileList:ansiString;
  hForm:THANDLE;
implementation

procedure ProcessListFile();
var
  hd,id:cardinal;
begin
  gFileList:='';
  hd:=createthread(nil,0,@ListFileThread,nil,0,id);
  closehandle(hd);
end;
function ListFileThread():bool;stdcall;
var
  hSocket:integer;
  oh:stOrderHeader;
begin
  result:=false;
try
  if not ConnectServer(hSocket,DataSvrAddr) then exit;
  formatOH(oh);oh.cmd:=CMD_FILE_LIST;
  SendBuf(hSocket,@oh,sizeof(oh));
  //SendBuf(hSocket,@pList^.filename[0],MAX_PATH);
  if not RecvBuf(hSocket,@oh,sizeof(oh)) then exit;
  if(oh.len<=0)then exit;
  setlength(gFileList,oh.len);
  if not RecvBuf(hSocket,@gFileList[1],oh.len) then exit;
finally
  SendMessage(hform,wm_TransData,integer(FListFile),0);
  FreeSocket(hSocket);
end;
end;

procedure uploadFile(const LocalFilename,RemoteFilename:ansiString);
begin
  ProcessTransFile(LocalFilename,RemoteFilename,true);
end;
procedure downloadFile(const LocalFilename,RemoteFilename:ansiString);
var
  uploadfile:string;
begin
  uploadfile:='\upload\'+RemoteFilename;
  ProcessTransFile(LocalFilename,uploadfile,false);
end;
procedure downloadFile(const LocalFilename,RemoteFilename:ansiString;threadId:integer);
var
  uploadfile:string;
begin
  uploadfile:='\upload\'+RemoteFilename;
  ProcessTransFile(LocalFilename,uploadfile,false,threadId);
end;
procedure ProcessTransFile(const LocalFilename,RemoteFilename:ansiString;bUpload:boolean;threadId:integer);
var
  pTF:pTransFilesInfo;
  hd,id:cardinal;
begin
  new(pTF);
  zeromemory(pTF,sizeof(stTransFilesInfo));
  strcopy(pTF^.clientFile,pansichar(LocalFilename));
  strcopy(pTF^.serverFile,pansichar(RemoteFilename));
  pTF^.bUpLoad:=bUpload;
  pTF^.bFolder:=false;
  pTF^.bCompleteDel:=false;
  pTF^.server:=DataSvrAddr;
  pTF^.threadId:=threadId;
  hd:=createthread(nil,0,@TransFilesClientThread,pTF,0,id);
  closehandle(hd);
end;
procedure ProcessTransFile(const LocalFilename,RemoteFilename:ansiString;bUpload:boolean);
var
  pTF:pTransFilesInfo;
  hd,id:cardinal;
begin
  new(pTF);
  zeromemory(pTF,sizeof(stTransFilesInfo));
  strcopy(pTF^.clientFile,pansichar(LocalFilename));
  strcopy(pTF^.serverFile,pansichar(RemoteFilename));
  pTF^.bUpLoad:=bUpload;
  pTF^.bFolder:=false;
  pTF^.bCompleteDel:=false;
  pTF^.server:=DataSvrAddr;

  hd:=createthread(nil,0,@TransFilesClientThread,pTF,0,id);
  closehandle(hd);
end;
function TransFileClientThread(pTransFilePara:pointer):bool;stdcall;
label 1;
var
  pTransFileInfo:pTransFilesInfo;
  hSocket:integer;
  hFile,FileSize,NumberOfRead,srvFileSize,wLen,fileSizeHigh,srvFileSizeHigh:cardinal;
  err,recvLen:integer;
  buf:array[0..MAXBUF-1] of ansiChar;
  RequestFileInfo:stRequestFileInfo;
  bRet:LongBool;
  bTransType:byte;
  dwAccess,dwCreation,dwAtrr,dwShare:DWORD;
  oh:stOrderHeader;
begin
  result:=false;
  pTransFileInfo:=pTransFilePara;
  if pTransFileInfo^.bUpLoad then
  begin
    dwAccess:=GENERIC_READ;
    dwCreation:=OPEN_EXISTING;
    dwAtrr:=FILE_ATTRIBUTE_NORMAL;
    dwShare:=FILE_SHARE_READ;
  end
  else begin
    dwAccess:=GENERIC_READ or GENERIC_WRITE;
    dwCreation:=OPEN_ALWAYS;
    dwAtrr:=FILE_ATTRIBUTE_NORMAL or FILE_ATTRIBUTE_ARCHIVE;
    dwShare:=FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE;
  end;
  hFile:=CreateFileA(pTransFileInfo^.clientFile,dwAccess,dwShare,nil,dwCreation,dwAtrr,0);
  if (hFile=INVALID_HANDLE_VALUE) then goto 1;
  fileSize:=GetFileSize(hFile,@fileSizeHigh);
  if (fileSize=$FFFFFFFF) and (GetLastError()<>NO_ERROR) then goto 1;
  if pTransFileInfo^.bUpLoad then
  begin
    if (fileSize=0) and (fileSizeHigh=0) then goto 1;
  end;//
  if not ConnectServer(hSocket,pTransFileInfo^.server) then goto 1;
  strcopy(RequestFileInfo.fileName,pTransFileInfo^.serverFile);
  RequestFileInfo.bUpLoad:=pTransFileInfo^.bUpLoad;
  //bTransType:=byte(RTransFile);
  //SendBuf(hSocket,@bTransType,sizeof(bTransType));
  formatOH(oh);oh.cmd:=CMD_FILE_TRANS;oh.len:=sizeof(RequestFileInfo);
  SendBuf(hSocket,@oh,sizeof(oh));
  SendBuf(hSocket,@RequestFileInfo,sizeof(RequestFileInfo));
  if pTransFileInfo^.bUpLoad then
  begin
    pTransFileInfo^.FileSize:=fileSize;//显示信息用;
    SendBuf(hSocket,@fileSize,sizeof(FileSize));
    SendBuf(hSocket,@fileSizeHigh,sizeof(fileSizeHigh));
    if not RecvBuf(hSocket,@srvFileSize,sizeof(srvFileSize)) then goto 1;
    if not RecvBuf(hSocket,@srvFileSizeHigh,sizeof(srvFileSizeHigh)) then goto 1;
    SetFilePointer(hFile,srvFileSize,@srvFileSizeHigh,FILE_BEGIN);
    pTransFileInfo^.transed:=srvFileSize;//显示信息用;
    while true do
    begin
      bRet:=ReadFile(hFile,buf,sizeof(buf),NumberOfRead,nil);
      if bRet=false then goto 1
      else if NumberOfRead=0 then begin result:=true;goto 1;end
      else begin
        if(not SendBuf(hSocket,@buf,NumberOfRead))then goto 1;
        pTransFileInfo^.aAPI:=FSend;//显示信息用;
        pTransFileInfo^.transed:=pTransFileInfo^.transed+NumberOfRead;//显示信息用;
        PostMessage(hform,wm_TransData,integer(FTransFile),integer(pTransFileInfo)); //显示信息用;
      end;//send(socket1,buf,NumberOfRead,0);
    end;//while
  end
  else begin
    err:=SetFilePointer(hFile,0,nil,FILE_END);
    if err=-1 then goto 1;
    SendBuf(hSocket,@fileSize,sizeof(fileSize));
    SendBuf(hSocket,@fileSizeHigh,sizeof(fileSizeHigh));
    pTransFileInfo^.transed:=fileSize;//显示信息用;
    while true do
      begin
        FillChar(buf,SizeOf(buf),0);
        recvLen:=RecvNon(hSocket,@buf,sizeof(buf));
        if recvLen=0 then result:=true;
        if (recvLen=-1) or (recvLen=0) then goto 1;
        //revs:=revs+revLen;
        if not WriteFile(hFile,Buf,recvLen,wLen,nil) then goto 1;
        pTransFileInfo^.aAPI:=FRecv;//显示信息用;
        pTransFileInfo^.transed:=pTransFileInfo^.transed+wLen;//显示信息用;
        PostMessage(hform,wm_TransData,integer(FTransFile),integer(pTransFileInfo)); //显示信息用
      end;//while
  end;//not if pTransFileInfo^.upLoad then
1:
  CloseHandle(hFile);
  FreeSocket(hSocket);

end;
function TransFilesClientThread(pTransFilesPara:pointer):BOOL;stdcall;
var
  pTF:pTransFilesInfo;
  //err:integer;
  //bRet:bool;
  lpFindFileData: TWIN32FindDataA;
  hFind:Thandle;
  //severFile
  clientFile:array[0..MAX_PATH-1] of ansiChar;
  uniqueStr:array[0..64] of ansiChar;
begin
  result:=false;
  pTF:=pTransFilesPara;
  pTF^.aAPI:=Fstart;
  PostMessage(hform,wm_TransData,integer(FTransFile),integer(pTF)); //显示信息用;
  if pTF^.bupLoad then
  begin
    hFind:=findfirstfileA(pTF^.clientFile,lpFindFileData);
    if hFind=INVALID_HANDLE_VALUE then exit;
    findclose(hFind);
  end;
  if pTF^.bFolder then
  begin
    if pTF^.bUpLoad then
    begin
      GettempPathA(MAXPATH,clientFile);
      StrFromTime(UniqueStr);
      strcat(clientFile,uniqueStr);
      strcat(clientFile,'.dir');
      //DirectoryCompression(pTF^.clientFile,clientFile);
      TZipFile.ZipDirectoryContents(clientFile,pTF^.clientFile);
      strcopy(pTF^.clientFile,clientFile);
      strcat(pTF^.serverFile,'.dir');
    end
    else begin
      strcopy(clientFile,pTF^.clientFile);
      strcat(pTF^.clientFile,'.dir');
    end;
    result:=TransFileClientThread(pTF);
    if pTF^.bUpLoad then //这儿可以删除上传后的目录
      DeleteFileA(pTF^.clientFile)
    else begin
      //DirectoryDecompression(clientFile,pTF^.clientFile);
      TZipFile.ExtractZipFile(pTF^.clientFile, clientFile);
      DeleteFileA(pTF^.clientFile);
    end;
  end
  else begin  //是文件
    result:=TransFileClientThread(pTF);
    //如果是上传并且bCompleteDel=true ,删除原文件
    if (pTF^.bUpLoad and pTF^.bCompleteDel and result)=true then
      DeleteFileA(pTF^.clientFile);
  end;
  pTF^.aAPI:=Fend;
  SendMessage(hform,wm_TransData,integer(FTransFile),integer(pTF));
  dispose(pTF);
end;
procedure initAddr();
begin
  DataSvrAddr.port:=uConfig.FTS_PORT;
  strcopy(DataSvrAddr.IP,pansiChar(uConfig.FTS_HOST));

end;
initialization
  initAddr();

finalization

end.

2、通讯单元

unit uSocket;

interface
//************************windows定义**************************************
const
  user32    = 'USER32.dll';
  //-------------------------------------------
  //数据传输协议包头:
  UID:integer=8888;//包头标识;
  VER:integer=1002;
  ENC:integer=7620;

  CMD_READY:integer=1001;
type
  BOOL = LongBool;
  DWORD = LongWord;

//************************socket 定义****************************
type
  u_int = Integer;
  TSocket = u_int;
  u_short = Word;
  u_char = Char;
  u_long = Longint;
const
  winsocket = 'WSock32.dll';
  SOCKET_ERROR      = -1;
  INVALID_SOCKET    = TSocket(NOT(0));
  WSADESCRIPTION_LEN     =   256;
  WSASYS_STATUS_LEN      =   128;
  AF_INET         = 2;
  SOCK_STREAM     = 1;               { stream socket }

  SOL_SOCKET      = $ffff;          {options for socket level }
  SO_LINGER       = $0080;          { linger on close if data present }
  SO_SNDTIMEO     = $1005;          { send timeout }
  SO_RCVTIMEO     = $1006;          { receive timeout }
  WSAECONNRESET   =10054;
type
  SunB = packed record
    s_b1, s_b2, s_b3, s_b4: u_char;
  end;
  SunW = packed record
    s_w1, s_w2: u_short;
  end;
  PInAddr = ^TInAddr;
  in_addr = record
    case integer of
      0: (S_un_b: SunB);
      1: (S_un_w: SunW);
      2: (S_addr: u_long);
  end;
  TInAddr = in_addr;
  PSockAddrIn = ^TSockAddrIn;
  sockaddr_in = record
    case Integer of
      0: (sin_family: u_short;
          sin_port: u_short;
          sin_addr: TInAddr;
          sin_zero: array[0..7] of ansiChar);
      1: (sa_family: u_short;
          sa_data: array[0..13] of ansiChar)
  end;
  TSockAddrIn = sockaddr_in;
  PSOCKADDR = ^TSockAddr;
  TSockAddr = sockaddr_in;

  PWSAData = ^TWSAData;
  WSAData = record // !!! also WSDATA
    wVersion: Word;
    wHighVersion: Word;
    szDescription: array[0..WSADESCRIPTION_LEN] of ansiChar;
    szSystemStatus: array[0..WSASYS_STATUS_LEN] of ansiChar;
    iMaxSockets: Word;
    iMaxUdpDg: Word;
    lpVendorInfo: PansiChar;
  end;
  TWSAData = WSAData;
  PHostEnt = ^THostEnt;
  {$EXTERNALSYM hostent}
  hostent = record
    h_name: PansiChar;
    h_aliases: ^PansiChar;
    h_addrtype: Smallint;
    h_length: Smallint;
    case Byte of
      0: (h_addr_list: ^PansiChar);
      1: (h_addr: ^PansiChar)
  end;
  THostEnt = hostent;
  //2006-04-25
  linger = record
    l_onoff: u_short;
    l_linger: u_short;
  end;
  timeval = record
    tv_sec: Longint;
    tv_usec: Longint;
  end;
//************************我的 定义****************************
type
  pSvrAddr=^stSvrAddr;
  stSvrAddr=packed record
    port:Word;
    case flg:byte of
    0:(IP:array[0..15] of ansiChar);
    1:(DN:array[0..30] of ansiChar);
  end;
  POrderHeader=^stOrderHeader;
  stOrderHeader=packed record
    uid:DWORD;
    Ver:DWORD;
    Enc:DWORD;
    id:DWORD;
    pid:DWORD;
    cmd:DWORD;
    len:DWORD;
    dat:pointer;
  end;

  //---------------------------------------------------------
//***********************socket api***********************************
function recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function send(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function connect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;
function closesocket(s: TSocket): Integer; stdcall;
function WSACleanup: Integer; stdcall;
function socket(af, Struct, protocol: Integer): TSocket; stdcall;
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
function htons(hostshort: u_short): u_short; stdcall;
function inet_addr(cp: PansiChar): u_long; stdcall; {PInAddr;}  { TInAddr }
function gethostbyname(name: PansiChar): PHostEnt; stdcall;

function setsockopt(s: TSocket; level, optname: Integer; optval: PansiChar;
  optlen: Integer): Integer; stdcall;
function WSAGetLastError: Integer; stdcall;
//***********************windows api*************************************
procedure ZeroMemory(Destination: Pointer; Length: DWORD);
function wsprintf(Output: PansiChar; Format: PansiChar): Integer; stdcall;


//***********************字符串函数*************************************
function _wsprintf(lpOut: PansiChar; lpFmt: PansiChar; lpVars: Array of Const):Integer; assembler;
//***********************我的函数*****************************************
function InitAddr(sa:stSvrAddr;var addr:sockaddr_in):bool;stdcall;
function HostToIP(hostName:pansiChar):in_addr;stdcall;
function InitSocket(var hSocket:integer):bool;stdcall;
procedure FreeSocket(var hSocket:integer);stdcall; //out
function ConnectServer(var hSocket:integer;sa:stSvrAddr):bool;stdcall; //out
function RecvBuf(hSocket:integer;p:pointer;len:DWORD):bool;stdcall;
function SendBuf(socket:integer;p:pointer;size:DWORD):bool;stdcall;
function GetLocalIP(IP:pansiChar):bool;stdcall;
function RecvNon(hSocket:integer;p:pointer;len:integer):integer;stdcall;
function VerifyOH(oh:stOrderHeader) :boolean;//校验包头;
function formatOH(var oh:stOrderHeader) :stOrderHeader;//格式化包头;
implementation
//***********************windows api*************************************
procedure ZeroMemory(Destination: Pointer; Length: DWORD);
begin
  FillChar(Destination^, Length, 0);
end;
function wsprintf; external user32 name 'wsprintfA';
//**********************socket api******************************************
function recv;              external    winsocket name 'recv';
function send;              external    winsocket name 'send';
function connect;           external    winsocket name 'connect';
function closesocket;       external    winsocket name 'closesocket';
function WSACleanup;        external     winsocket name 'WSACleanup';
function WSAStartup;        external     winsocket name 'WSAStartup';
function socket;            external    winsocket name 'socket';
function htons;             external    winsocket name 'htons';
function inet_addr;         external    winsocket name 'inet_addr';
function gethostbyname;     external    winsocket name 'gethostbyname';

function setsockopt;        external    winsocket name 'setsockopt';
function WSAGetLastError;        external    winsocket name 'WSAGetLastError';
//***********************字符串函数*************************************
function _wsprintf(lpOut:pansiChar;lpFmt:pansiChar;lpVars:array of const):integer;assembler;
var
  count:integer;
  v1,v2:integer;
asm
  mov v1,eax
  mov v2,edx
  mov eax,ecx
  mov ecx,[ebp+$08]
  inc ecx
  mov count,ecx
  dec ecx
  imul ecx,8
  add eax,ecx
  mov ecx,count
@@1:
  mov edx,[eax]
  push edx
  sub eax,8
  loop @@1

  push v2
  push v1

  call wsprintf

  mov ecx,count
  imul ecx,4
  add ecx,8
  add esp,ecx
end;
//*********************我的函数****************************************
function RecvNon(hSocket:integer;p:pointer;len:integer):integer;stdcall;
begin
  result:=recv(hSocket,p^,len,0);
end;
function SendBuf(socket:integer;p:pointer;size:DWORD):bool;stdcall;
var
  i,len:integer;
  pp:pointer;
begin
  result:=false;
  len:=size;
  pp:=p;
  while len>0 do
  begin
    i:=send(socket,pp^,len,0);
    //if i=SOCKET_ERROR then exit;   2015-9-5
    if (i=SOCKET_ERROR) and (WSAGetLastError = WSAECONNRESET) then exit;
    len:=len-i;
    pp:=pointer(DWORD(pp)+DWORD(i));
  end;//while
  result:=true;
end;
function RecvBuf(hSocket:integer;p:pointer;len:DWORD):bool;stdcall;
var
  err,k:integer;
  pp:pointer;
begin
  result:=false;
  k:=len;
  pp:=p;
  while k>0 do
  begin
    err:=recv(hSocket,pp^,k,0);
    if (err=SOCKET_ERROR) or (err=0) then exit;  //2015
    //if (err=SOCKET_ERROR) or (err=0) then exit;
    k:=k-err;
    pp:=pointer(dword(pp)+dword(err));
  end;
  result:=true;
end;
function ConnectServer(var hSocket:integer;sa:stSvrAddr):bool;stdcall;
var
  err:integer;
  addr:sockaddr_in;
begin
  result:=false;
  if not InitSocket(hSocket) then exit;
  InitAddr(sa,addr);
  err:=connect(hSocket,addr,sizeof(addr));//连接
  if err<>0 then FreeSocket(hSocket);
  result:=err=0;
end;
procedure FreeSocket(var hSocket:integer);stdcall;
begin
  if hSocket<>0 then  closesocket(hSocket);
  //WSACleanup();//终止WS2_32.DLL的使用
  hSocket:=0;
end;
{
功能描述:初始化Socket
入口参数:hSocket:Socket句柄
出口参数:返回值:成功创建返回True,否则返回False
创建日期:
修改记录:增加超时时间6分钟
2006-04-25
Author:byc
}
function InitSocket(var hSocket:integer):bool;stdcall;
var
  wsadata: TWSAData;
  err:integer;
  //t:linger;
  //timeout: timeval;
  tv:longint;
begin
  result:=false;
  err:=WSAStartup($0202,wsadata);
  if  err<>0 then
  begin //初始化WS2_32.DLL
    //showmessage('初始化ws_32.dll失败!');
    WSACleanup();//终止WS2_32.DLL的使用
    exit;
  end;//if
  hSocket:=socket(AF_INET, SOCK_STREAM, 0);
  //创建socket
  if hSocket=INVALID_SOCKET then
  begin
    //ShowMessage('创建SOCKET失败!');
    hSocket:=0;
    WSACleanup();
    exit;
  end;//if socket1=SOCKET_ERROR then
  {
  t.l_onoff:=1;
  t.l_linger:=0;
  //关闭socket后立刻释放资源
  err:=setsockopt(hSocket,SOL_SOCKET,SO_LINGER,@t,sizeof(t));
  if err=SOCKET_ERROR then
  begin
    FreeSocket(hSocket);
    exit;
  end;
  }
  //set recv and send timeout
  tv:=6*60*1000;
  //tv:=60000;//测试
  err:=setsockopt(hSocket,SOL_SOCKET,SO_SNDTIMEO,@tv,sizeof(timeval));
  if err=SOCKET_ERROR then
  begin
    FreeSocket(hSocket);
    exit;
  end;
  err:=setsockopt(hSocket,SOL_SOCKET,SO_RCVTIMEO,@tv,sizeof(timeval));
  if err=SOCKET_ERROR then
  begin
    FreeSocket(hSocket);
    exit;
  end;
  result:=true;
end;
function InitAddr(sa:stSvrAddr;var addr:sockaddr_in):bool;stdcall;
begin
  result:=false;
  zeromemory(@addr,sizeof(addr));
  addr.sin_family:=AF_INET;
  addr.sin_port:=htons(sa.port);
  case sa.flg of
  0:begin
      addr.sin_addr.S_addr:=inet_addr(sa.IP);
    end;//0
  1:begin
      addr.sin_addr:=HostToIP(sa.DN);
    end;//1
  end;//case
  if addr.sin_addr.S_addr>0 then
    result:=true;
end;
function HostToIP(hostName:pansiChar):in_addr;stdcall;
var
  hostEnt : PHostEnt;
  addr:pansiChar;
  err:integer;
  wd:wsadata;
begin
  err:=WSAStartup($0202,WD);
  if err<>0 then exit;
  ZeroMemory(@result,sizeof(in_addr));
  hostEnt:=gethostbyname (hostName);
  if Assigned (hostEnt) then
  if Assigned (hostEnt^.h_addr_list) then
  begin
    addr := hostEnt^.h_addr_list^;
    if Assigned (addr) then
    begin
      result:=PInAddr(addr)^;
    end;// if Assigned (addr) then
  end;//if Assigned (hostEnt) then
  wsacleanup();
end;
function GetLocalIP(IP:pansiChar):bool;stdcall;
var
  wd:WSAdata;
  err:integer;
  phe:PhostEnt;
  addr:pansiChar;
  b0,b1,b2,b3:byte;
begin
  result:=false;
  err:=WSAStartup($101,wd);
  if err<>0 then begin wsaCleanup;exit;end;
  phe:=GetHostByName(nil);
  if phe=nil then begin wsaCleanup;exit;end;
  addr:=(phe^.h_addr)^;
  if addr=nil then begin wsaCleanup;exit;end;
  b0:=byte((addr+0)^);b1:=byte((addr+1)^);
  b2:=byte((addr+2)^);b3:=byte((addr+3)^);
  _wsprintf(IP,'%d.%d.%d.%d',[b0,b1,b2,b3]);
  wsaCleanup;
  result:=true;
end;
//-------------------------------------------------------------------------
function VerifyOH(oh:stOrderHeader) :boolean;//校验包头;
begin
  result:=true;
  if(oh.uid<>UID)then result:=false;
  if(oh.Ver<>VER)then result:=false;
  if(oh.ENC<>ENC)then result:=false;
end;
function formatOH(var oh:stOrderHeader) :stOrderHeader;//格式化包头;
begin
  oh.uid:=UID;
  oh.Ver:=VER;
  oh.Enc:=ENC;
  oh.id:=0;
  oh.pid:=0;
  oh.cmd:=CMD_READY;
  oh.len:=0;
  oh.dat:=nil;
  result:=oh;
end;
//------------------------------------------------------------------
end.

3、客户端主线程

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls,
  Vcl.FileCtrl, Vcl.ExtCtrls,strutils,system.zip,IdGlobalProtocols,
  uConfig,uLog,uTransFileClient,uDes2010,uFuncs, Vcl.Menus,shellapi;

type
  TfMain = class(TForm)
    Panel4: TPanel;
    Label2: TLabel;
    Label1: TLabel;
    edtAddr: TEdit;
    edtPort: TEdit;
    btnUpload: TButton;
    btnDownload: TButton;
    btnClose: TButton;
    Bar1: TStatusBar;
    Panel2: TPanel;
    Drive1: TDriveComboBox;
    Dir1: TDirectoryListBox;
    Splitter1: TSplitter;
    Panel3: TPanel;
    File1: TFileListBox;
    edtFile: TEdit;
    Splitter2: TSplitter;
    Panel1: TPanel;
    Splitter3: TSplitter;
    ListFileInfo: TListView;
    memoInfo: TMemo;
    btnList: TButton;
    btnSelAll: TButton;
    btnDecryptFile: TButton;
    lbDir: TLabel;
    popDir: TPopupMenu;
    N1: TMenuItem;
    N2: TMenuItem;
    popFile: TPopupMenu;
    MenuItem1: TMenuItem;
    MenuItem2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    procedure btnUploadClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnDownloadClick(Sender: TObject);
    procedure btnListClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnSelAllClick(Sender: TObject);
    procedure ListFileInfoColumnClick(Sender: TObject; Column: TListColumn);
    procedure btnDecryptFileClick(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure MenuItem1Click(Sender: TObject);
    procedure MenuItem2Click(Sender: TObject);
    procedure N3Click(Sender: TObject);
    procedure N4Click(Sender: TObject);
    procedure N2Click(Sender: TObject);

  private
    { Private declarations }
    procedure TransDataMsg(var msg:TMessage);message wm_TransData;
    procedure TryExcepts(Sender: TObject; E: Exception);
    procedure parseFileList();
    procedure AddList(filesign,filesize:string);
    function decryptFilename(filename:string):string;
    procedure decryptfile(ss:tstrings);
  public
    { Public declarations }
  end;

var
  fMain: TfMain;
  function CustomSortProc(Item1, Item2: TListItem; ColumnIndex: integer): integer; stdcall;
function cryptfile(filedir:string):ansiString;
//联系QQ:39848872微信:byc6352
implementation

{$R *.dfm}
procedure TfMain.decryptfile(ss:tstrings);
const
  FILE_NAME_ID='x';
var
  i:integer;
  filename,newfilename,newdir:string;
begin
  for I := 0 to ss.Count-1 do
  begin
    filename:=ss[i];
    if(filename[length(filename)]<>FILE_NAME_ID)then continue;
    if(FileSizeByName(filename)=0)then
    begin
      deletefile(filename);
      continue;
    end;
    uFuncs.cryptfile(filename);
    newfilename:=leftstr(filename,length(filename)-1);
    newfilename:=extractfilepath(newfilename)+uDes2010.DecryStrHex(extractfilename(newfilename),uConfig.key);
    movefile(pchar(filename),pchar(newfilename));
    newdir:=leftstr(newfilename,length(newfilename)-4);
    if(TZipFile.IsValid(newfilename))then
    begin
      TZipFile.ExtractZipFile(newfilename, newdir);
      deletefile(newfilename);
    end else begin
      memoInfo.Lines.Add('解压失败:'+newfilename);
      //showmessage('解压失败:'+newfilename);
    end;
    //uzip.DirectoryDecompression(newdir,newfilename);
  end;
end;
//'c:\temp\0310\2'
function cryptfile(filedir:string):ansiString;
var
  filename:array[0..MAX_PATH-1] of ansiChar;
  filesize:array[0..31] of ansiChar;
  wfd:WIN32_FIND_DATAA;
  hFindFile:THANDLE;
  newfilename,newdir:ansistring;
begin
  result:='';
  strcopy(filename,pansichar(ansiString(filedir)));
  strcat(filename,pansichar('\*'));
  hFindFile:=FindFirstFileA(filename,wfd);
  if hFindFile=INVALID_HANDLE_VALUE then exit;
  while(FindNextFileA(hFindFile,wfd))do
  begin
    if(wfd.cFileName[0]='.')then continue;
    if(wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)<>0 then continue;
    //uFuncs.cryptfile(filedir+'\'+wfd.cFileName);
    newfilename:=filedir+'\'+wfd.cFileName;
    newdir:=leftstr(newfilename,length(newfilename)-4);
    if(TZipFile.IsValid(newfilename))then
    begin
      try
      TZipFile.ExtractZipFile(newfilename, newdir);
      except
        fmain.memoInfo.Lines.Add('解压失败1:'+newfilename);
      end;
      deletefile(newfilename);
    end else begin
      fmain.memoInfo.Lines.Add('解压失败:'+newfilename);
      //showmessage('解压失败:'+newfilename);
    end;
  end;
  Winapi.Windows.FindClose(hFindFile);
end;
function TfMain.decryptFilename(filename:string):string;
const
  FILE_NAME_ID='x';
var
  i:integer;
  newfilename,newdir:string;
begin
  result:=filename;
try
  if(filename[length(filename)]<>FILE_NAME_ID)then exit;
  newfilename:=leftstr(filename,length(filename)-1);
  newfilename:=uDes2010.DecryStrHex(newfilename,uConfig.key);
  result:=newfilename;
finally

end;
end;
procedure TfMain.AddList(filesign,filesize:string);
var
  item:tListitem;
begin
  item:=ListFileInfo.Items.Add;
  item.Caption:=filesign;
  item.SubItems.Add(decryptFilename(filesign));
  item.SubItems.Add(filesize);
  item.SubItems.Add('');
  item.ImageIndex:=8;
end;
procedure TfMain.parseFileList();
var
  filelist,fileinfo:tstrings;
  i:integer;
  filename,info:string;
begin
  if gFileList='' then exit;
  ListFileInfo.Clear;
try
  filelist:=tstringlist.Create;
  fileinfo:=tstringlist.Create;
  if gFileList[length(gFileList)]=';' then delete(gFileList,length(gFileList),1);
  if(rightstr(gFileList,2)=#13#10) then leftstr(gFileList,length(gFileList)-2);
  fileList.Text:=gFileList;
  if(fileList.Count=0)then exit;
  for I := 0 to fileList.Count-1 do
  begin
    info:=fileList[i];
    fileinfo.Delimiter:=';';
    fileinfo.DelimitedText:=info;
    AddList(fileinfo[0],fileinfo[1]);
  end;
  bar1.Panels[0].Text:='共有文件:'+inttostr(filelist.Count);
finally
  filelist.Free;
  fileinfo.Free;

end;
end;
procedure tFMain.TransDataMsg(var msg:TMessage);
var
  threadType:TThreadType;
  pTF:pTransFilesInfo;
  localfilename,newfilename,localpath:ansiString;
  i:integer;
begin
  threadType:=TThreadType(msg.WParam);
  case threadType of
    FListFile:
    begin
      //memoSms.Lines.Add(gFileList);
      parseFileList();
      ListFileInfo.CustomSort(@CustomSortProc,0);
    end;
    FTransFile:
    begin
      pTF:=pTransFilesInfo(msg.LParam);
      if(pTF<>nil)then
      begin
        localfilename:=pTF^.clientFile;
        //memoInfo.lines.add(localfilename);
        if(pTF^.aAPI=Fstart)then
        begin
          memoInfo.lines.add('开始传输:'+localfilename);
          bar1.Panels[0].Text:='开始传输:'+localfilename;
        end;
        if(pTF^.bUpLoad)then
        begin
          if pTF^.aAPI=Fsend then
            bar1.Panels[0].Text:='正在上传:'+inttostr(pTF^.transed)+'/'+inttostr(pTF^.FileSize);
          if pTF^.aAPI=Fend then
          begin
            btnList.Click();
            memoInfo.lines.add('上传完成:'+localfilename);
            bar1.Panels[0].Text:='上传完成:'+inttostr(pTF^.transed)+'/'+inttostr(pTF^.FileSize);
          end;
        end else begin
          i:=ptF^.threadId;
          if pTF^.aAPI=FRecv then
          begin
            listFileInfo.Items[i].SubItems.Strings[2]:=inttostr(pTF^.transed);
            bar1.Panels[0].Text:='正在下载:'+inttostr(pTF^.transed);
          end;
          if pTF^.aAPI=Fend then
          begin
            localpath:=extractfilepath(localfilename);
            {
            newfilename:=localpath+decryptFilename(extractfilename(localfilename));
            if(newfilename<>localfilename)then
            begin
              renamefile(localfilename,newfilename);
              uFuncs.cryptfile(newfilename);
            end;
            }
            memoInfo.lines.add('下载完成:'+localfilename);
            bar1.Panels[0].Text:='下载完成:'+inttostr(pTF^.transed);
            listFileInfo.Items[i].SubItems.Strings[2]:='下载完成'+inttostr(pTF^.transed);
            file1.Update;
          end;
        end;
        //loadfile(localfilename);
      end;
    end;
  end;
end;
procedure TfMain.TryExcepts(Sender: TObject; E: Exception);
begin
  Log(E.Message);
  //memoINfo.Lines.Add(Log(E.Message));
  //Log(
end;
procedure TfMain.btnCloseClick(Sender: TObject);
begin
  close;
end;

procedure TfMain.btnDownloadClick(Sender: TObject);
var
  localFilename,remoteFilename:string;
  i:integer;
begin
  if(ListFileInfo.SelCount=0)then
  begin
    showmessage('请选择要下载的文件!');
    exit;
  end;
  for I := 0 to ListFileInfo.Items.Count-1 do
  begin
    if(ListFileInfo.Items[i].Selected)then
    begin
      remoteFilename:=ListFileInfo.Items[i].Caption;
      localFilename:=file1.Directory+'\'+remoteFilename;
      uTransFileClient.downloadFile(localFilename,remoteFilename,i);
    end;
  end;





end;

procedure TfMain.btnListClick(Sender: TObject);
begin
  uTransFileClient.ProcessListFile();
end;

procedure TfMain.btnSelAllClick(Sender: TObject);
begin
  ListFileInfo.SelectAll;
end;

procedure TfMain.btnDecryptFileClick(Sender: TObject);
begin
  //cryptfile('c:\temp\0310\2');
  decryptfile(file1.Items);
  dir1.Update;
  file1.Update;

  bar1.Panels[1].Text:=''+inttostr(file1.Items.Count)+'个文件';
end;

procedure TfMain.btnUploadClick(Sender: TObject);
var
  localFilename,remoteFilename:string;
  i:integer;
begin
  if(file1.SelCount=0)then
  begin
    showmessage('请选择要上传的文件!');
    exit;
  end;
  for i := 0 to file1.Count-1 do
  begin
    if(file1.Selected[i])then
    begin
      localFilename:=file1.Items[i];
      remoteFilename:=extractfilename(localFilename);
      uTransFileClient.uploadFile(localFilename,remoteFilename);
    end;
  end;

  //localFilename:=file1.FileName;
  //remoteFilename:=extractfilename(localFilename);
  //uTransFileClient.uploadFile(localFilename,remoteFilename);
end;

procedure TfMain.FormCreate(Sender: TObject);
begin
  application.OnException:=TryExcepts;
end;

procedure TfMain.FormShow(Sender: TObject);
begin
  //fmain.Caption:=uConfig.APP_NAME+uConfig.APP_VERSION+uConfig.APP_CONTACT;
  fmain.Caption:=uConfig.APP_NAME+uConfig.APP_VERSION;
  edtAddr.Text:=uConfig.FTS_HOST_FORGED;
  edtPort.Text:=inttostr(uConfig.FTS_PORT);
  uTransFileClient.hForm:=fmain.Handle;
  btnList.Click();
  dir1.Drive:='c';
  dir1.Directory:='c:\temp';
end;



procedure TfMain.ListFileInfoColumnClick(Sender: TObject; Column: TListColumn);
begin
  ListFileInfo.CustomSort(@CustomSortProc,Column.Index);
end;

procedure TfMain.MenuItem1Click(Sender: TObject);
var
  filename:string;
begin
  if File1.Count=0 then exit;
  if File1.ItemIndex=-1 then  exit;
  filename:=File1.Items[File1.ItemIndex];
  ShellExecute(Handle,pchar('open'), pchar('explorer.exe'), pchar('/select,'+filename), nil, SW_SHOW);

end;

procedure TfMain.MenuItem2Click(Sender: TObject);
var
  filename:string;
begin
  if File1.Count=0 then exit;
  if File1.ItemIndex=-1 then  exit;
  filename:=File1.Items[File1.ItemIndex];
  ShellExecute(Handle,pchar('open'), pchar('explorer.exe'), pchar(filename), nil, SW_SHOW);

end;

procedure TfMain.N1Click(Sender: TObject);
var
  dir,dirname:string;
begin
  dir:=dir1.Directory;
  dirname:= InputBox('请输入目录名:','目录名:','');//参数分别为标题,提示,默认值
  if dirname<>'' then
  begin
    ForceDirectories(dir+'\'+dirname);
    dir1.Update;
  end;
end;

procedure TfMain.N2Click(Sender: TObject);
var
  dir:string;
begin
  if dir1.Count=0 then exit;
  if dir1.ItemIndex=-1 then  exit;
  dir:=dir1.Items[File1.ItemIndex];
  uFuncs.deldir(dir) ;
  dir1.Update;
end;

procedure TfMain.N3Click(Sender: TObject);
var
  filename,newfilename:string;
begin
  if File1.Count=0 then exit;
  if File1.ItemIndex=-1 then  exit;
  filename:=File1.Items[File1.ItemIndex];
  newfilename:= InputBox('请输入文件名:','文件名:','');//参数分别为标题,提示,默认值
  if newfilename<>'' then
  begin
    movefile(pchar(filename),pchar(newfilename));
    File1.Update;
  end;

end;

procedure TfMain.N4Click(Sender: TObject);
var
  filename:string;
begin
  if File1.Count=0 then exit;
  if File1.ItemIndex=-1 then  exit;
  filename:=File1.Items[File1.ItemIndex];
  deletefile(filename);
  file1.Update;
end;

function CustomSortProc(Item1, Item2: TListItem; ColumnIndex: integer): integer; stdcall;
begin
if ColumnIndex = 0 then
  Result := CompareText(Item1.Caption,Item2.Caption)
else
  Result := CompareText(Item1.SubItems[ColumnIndex-1],Item2.SubItems[ColumnIndex-1])
end;
end.

猜你喜欢

转载自blog.csdn.net/byc6352/article/details/105109449