<%@Language=VBScript%> C++爱好者

 

Victor 控件使用方法详解 - TYbCommDevice

文件收发演示程序 (发送端和接收端都需要运行这个程序,接收端自动进行文件接收)

因为考虑速度和可靠性更重要, 程序采用数据包协议进行大量数据收发。
利用 ReadPackage 和 WritePackage 方法, 可发送和接收任意类型的数据包。

完整的例子:
UnitSendFile.h文件内容 (蓝色为新增内容):

//---------------------------------------------------------------------------

#ifndef UnitSendFileH
#define UnitSendFileH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "YbCommDevice.h"
#include <ActnList.hpp>
#include <StdActns.hpp>
#include <Buttons.hpp>
#include <ComCtrls.hpp>
#include "yb_base.h"
#include "UnitTsData.h"
#include <mmsystem.h>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
  TYbCommDevice *YbCommDevice1;
  TActionList *ActionList1;
  TFileOpen *FileOpen1;
  TBitBtn *BitBtn1;
  TProgressBar *ProgressBar1;
  TTimer *Timer1;
  TMemo *Memo1;
  void __fastcall FileOpen1Accept(TObject *Sender);
  void __fastcall YbCommDevice1Package(TObject *Sender, int NotifyType);
  void __fastcall Timer1Timer(TObject *Sender);
private: // User declarations
  TRelPath dlpath;
  TBinFile sf,df;
  bool bUploading;
  unsigned char PkgID;
  long nBytesToReceive, iReceivingCounter;
  __int64 iReceiveFileTime;
  void __fastcall ShowInfo(AnsiString s);
  int __fastcall UploadReq(AnsiString fname);
  int __fastcall UploadFileData(void);
  int __fastcall WaitforAnswer(unsigned char Cmd, unsigned char id);

public: // User declarations
  __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


UnitSendFile.cpp 文件
:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "UnitSendFile.h"
#include "yb_base.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "YbCommDevice"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
  PkgID = 0;
  dlpath.Relative = "download";
  nBytesToReceive = 0;
  iReceiveFileTime = 0;
  bUploading = false;
  iReceivingCounter = 0;

  TBinFileFuncs::MkDir(AnsiString(dlpath).c_str());
  YbCommDevice1->PackageType = cptFrameHeadTail;
  YbCommDevice1->PackageSize = 9000; //最大允许发送9000字节的数据包
  YbCommDevice1->UsePackage = true;

  YbCommDevice1->FrameSettings->FrameHead = 0xdb; //数据包头
  YbCommDevice1->FrameSettings->FrameTail = 0xde; //数据包尾
  YbCommDevice1->FrameSettings->FrameCtrl = 0xdc; //数据控制符

  try
   {
     YbCommDevice1->Active = true;
   }
  catch(Exception &e)
   {
     if(!YbCommDevice1->SettingsDialog(this,true))
     Application->Terminate();
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ShowInfo(AnsiString s)
{
  Memo1->Lines->Add(FormatDateTime("yyyy-mm-dd hh:nn:ss ",Now())+s);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FileOpen1Accept(TObject *Sender)
{
  try
  {
    bUploading = true;
    int nCode = UploadReq(FileOpen1->Dialog->FileName);
    if(nCode==0x88)nCode = UploadFileData();

    switch(nCode)
     {
       case 0x88: ShowInfo("发送成功!"); break;
       case 0xee: ShowInfo("发送文件错误!"); break;
       default : ShowInfo("超时,对方电脑没有反应。");break;
     }
   }
  __finally
   {
     bUploading = false;
     sf.Active = false; //关闭文件
   }
}
//---------------------------------------------------------------------------
int __fastcall TForm1::UploadReq(AnsiString fname)
{
  sf.FileName = fname;
  sf.OpenMode = TBinFile::omRead;
  sf.Active = true;

  TMyFinfoPkg finf; //发送文件信息数据包
  finf.cmd = mpcUpload;
  finf.id = PkgID++;
  TBinFileFuncs::GetFileName(finf.name, sf.FileName.c_str());
  finf.size = sf.Size;
  finf.time = sf.Time;
  finf.CRC = ~TCRC32().Check(&finf, sizeof(TMyFinfoPkg)-4);

  YbCommDevice1->WritePackage(&finf, sizeof(TMyFinfoPkg));
  ShowInfo("发送文件: "+sf.FileName);
  return WaitforAnswer(finf.cmd, finf.id);
}
//---------------------------------------------------------------------------
int __fastcall TForm1::UploadFileData(void)
{
  TMyFdataPkg fdata; //发送文件内容数据包
  long nFileSize = sf.Size, nTries;
  fdata.cmd = mpcFileData; //发送文件数据
  fdata.from = 0; //从文件第0个字节开始发送

  while((fdata.size=sf.Read(fdata.data,DataSize))>0)
   {
     fdata.id = PkgID++;
     fdata.CRC = ~TCRC32().Check(&fdata,sizeof(TMyFdataPkg)-4);

     for(nTries=2; nTries>0; nTries--)
      {
        YbCommDevice1->WritePackage(&fdata,sizeof(TMyFdataPkg));
        if(WaitforAnswer(fdata.cmd, fdata.id)==0x88)
           break;
      }
     if(!nTries)
      {
        return 0xee;
      }

     fdata.from += fdata.size;
     ProgressBar1->Position = TBinFileFuncs::MakePercent(fdata.from, nFileSize);
   }
  return 0x88;
}
//---------------------------------------------------------------------------
int __fastcall TForm1::WaitforAnswer(unsigned char Cmd, unsigned char id)
{
  TMyStatusPkg AnsPkg; //对方电脑回应的数据包
  int tm_start=timeGetTime(), tm_out=2000;
  while((int)(timeGetTime()-tm_start)<tm_out)
   {
     if(YbCommDevice1->ReadPackage(&AnsPkg,sizeof(TMyStatusPkg))==sizeof(TMyStatusPkg))
     if((AnsPkg.cmd==mpcStatus) && (AnsPkg.id==id) && (AnsPkg.anscmd==Cmd))
      {
        if(AnsPkg.status == 0x88)
           return 0x88; //ok
        return 0xee; //error
      }
     Application->ProcessMessages();
   }
  return 0; //timeout
}
//---------------------------------------------------------------------------
void __fastcall TForm1::YbCommDevice1Package(TObject *Sender, int NotifyType)
{
  if((NotifyType==EV_RXCHAR) && !bUploading)
   {
     typedef union
      {
        TMyFinfoPkg finfo; //文件信息数据包
        TMyFdataPkg fdata; //文件内容数据包
        unsigned char cmd; //无论哪种数据包,第一个字节都是命令字节
      } TMyPackage;
     TMyPackage recv; //收到的数据包可能是文件信息或者文件内容
     TMyStatusPkg send; //发送回应状态数据包
     int nReceived; //收到的字节数

     while((nReceived=YbCommDevice1->ReadPackage(&recv,sizeof(TMyPackage)))>4) //数据包的长度都大于4
      {
        if(recv.cmd==mpcUpload)
         {
           send.cmd = mpcStatus;
           send.id = recv.finfo.id;
           send.anscmd = recv.finfo.cmd;
           send.status = (recv.finfo.CRC == ~TCRC32().Check(&recv,nReceived-4))?0x88:0xee;
           send.CRC = ~TCRC32().Check(&send,sizeof(TMyStatusPkg)-4);

           if(send.status==0x88) //数据 CRC 校验正确
            {
              iReceivingCounter = 5; //超过5秒没有数据,认为超时,中断接收
              nBytesToReceive = recv.finfo.size;
              iReceiveFileTime = recv.finfo.time;
              df.FileName = dlpath.FileName(recv.finfo.name);
              df.OpenMode = TBinFile::omCreateNew;
              df.Active = true;
              ShowInfo("接收文件: "+df.FileName);
 
              if(nBytesToReceive<=0)
               {
                 df.Time = iReceiveFileTime;
                 df.Active = false;
                 ShowInfo("接收完成!");
               }
            }
           YbCommDevice1->WritePackage(&send,sizeof(TMyStatusPkg));
         }
        else if(recv.cmd==mpcFileData)
         {
           send.cmd = mpcStatus;
           send.id = recv.fdata.id;
           send.anscmd = recv.fdata.cmd;
           send.status = recv.fdata.CRC == ~TCRC32().Check(&recv,nReceived-4)?0x88:0xee;
           send.CRC = ~TCRC32().Check(&send,sizeof(TMyStatusPkg)-4);

           if((send.status==0x88) && (df.Active)) //数据 CRC 校验正确
            {
              iReceivingCounter = 5; //超过5秒没有数据,认为超时,中断接收
              df.Pos = recv.fdata.from;
              df.Write(recv.fdata.data,recv.fdata.size);
              if(recv.fdata.from+recv.fdata.size>=nBytesToReceive)
               {
                 df.Time = iReceiveFileTime;
                 df.Active = false;
                 ShowInfo("接收完成!");
               }
              ProgressBar1->Position = TBinFileFuncs::MakePercent(recv.fdata.from+recv.fdata.size,nBytesToReceive);
            }
           YbCommDevice1->WritePackage(&send,sizeof(TMyStatusPkg));
         }
      }
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  if(iReceivingCounter>0)
   if(--iReceivingCounter==0)
    {
     if(df.Active)
      {
        df.Time = iReceiveFileTime;
        df.Active = false;
        ShowInfo("超时,接收中断。");
      }
    }
}
//---------------------------------------------------------------------------


程序使用的数据结构
:

//---------------------------------------------------------------------------

#ifndef UnitTsDataH
#define UnitTsDataH
//---------------------------------------------------------------------------
#include "yb_base.h"
//---------------------------------------------------------------------------
const DataSize=8192;
#pragma pack(push,1)
enum TMyPkgCmd
{
  mpcUpload = 1,
  mpcFileData = 2,
  mpcStatus = 3,
};

typedef struct
{
  unsigned char cmd; //1 (1: upload, 2: filedata, 3:status)
  unsigned char id;
  __int64 time; //date & time
  long size; //filesize
  char name[MAXPATH]; //filename
  unsigned long CRC;
} TMyFinfoPkg;

typedef struct
{
  unsigned char cmd; //2 (1: upload, 2: filedata, 3:status)
  unsigned char id;
  long from;
  long size;
  char data[DataSize];
  unsigned long CRC;
} TMyFdataPkg;

typedef struct
{
  unsigned char cmd; //3
  unsigned char id;
  unsigned char anscmd;
  unsigned char status; //0x88: OK
  unsigned long CRC;
} TMyStatusPkg;

#pragma pack(pop)
//---------------------------------------------------------------------------
#endif

返回 TYbCommDevice

C++ 爱好者
-- Victor Chen 的个人主页
网址: http://www.cppfans.com/
Email: victor@cppfans.com
本站可以互相交换相关内容网站的链接
本站拒绝任何毫无相关的广告和链接