⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sendfile_cpp.cpp

📁 一个在delphi下用udp传输文件的实例
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "SendFile_Cpp.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TSendFiles *SendFiles;
//---------------------------------------------------------------------------
__fastcall TSendFiles::TSendFiles(TComponent* Owner)
        : TForm(Owner)
{
FullFileName=new TStringList();//要发送的全路经文件名
FSTimeOut=0;                   //命令超时计数器
BuildTable16(cnCRC_CCITT);     //建立CRC校验表
SleepTime=30;
}
//---------------------------------------------------------------------------


//****************设置文件保存路径******************
void __fastcall TSendFiles::Button5Click(TObject *Sender)
{
  AnsiString Dir0 = "";
  if (SelectDirectory(Dir0, TSelectDirOpts() << sdAllowCreate << sdPerformCreate << sdPrompt,0)) Dir->Text = Dir0;
}
//---------------------------------------------------------------------------


//****************完成设置,返回主画面***************
void __fastcall TSendFiles::Button4Click(TObject *Sender)
{
Notebook1->ActivePage="Main";
}
//---------------------------------------------------------------------------


//****************进入设置画面*******************
void __fastcall TSendFiles::SetUpClick(TObject *Sender)
{
Notebook1->ActivePage="SetUp";
}
//---------------------------------------------------------------------------


//****************添加按钮事件*******************
void __fastcall TSendFiles::AddClick(TObject *Sender)
{
AnsiString FileName,TempName;                         //文件名
if (OpenDialog1->Execute())                           //打开文件对话框
  {
    for (int i=0;i<OpenDialog1->Files->Count;i++)
        {
         TempName=OpenDialog1->Files->Strings[i];     //取出全路经文件名
         FullFileName->Add(TempName);                 //保存
         FileName=ExtractFileName(TempName);          //取出无路经文件名
         ListView1->AddItem(FileName,NULL);           //在ListView中显示
        }
   Sent->Enabled=true;                                //发送按钮
   Cancel->Enabled=false;                             //取消按钮
  }
}
//---------------------------------------------------------------------------


void __fastcall TSendFiles::ListView1Resize(TObject *Sender)
{
ListView1->Columns->Items[0]->Width=ListView1->Width-5;
}
//---------------------------------------------------------------------------


//*****************清除**************************
void __fastcall TSendFiles::ClearClick(TObject *Sender)
{
FullFileName->Clear();
ListView1->Clear();
Sent->Enabled=false;
Cancel->Enabled=false;
Add->Enabled=true;
FSCMDS->Lines->Clear();
FRCMDS->Lines->Clear();
FSRepa->Lines->Clear();
FRError->Lines->Clear();
}
//---------------------------------------------------------------------------


//**************************发送数据到UDP控件************************
//**参数:CMD---命令码,Buffer---缓冲去指针,Size---数据长度
//*******************************************************************
void __fastcall TSendFiles::SendData_1(AnsiString CMD,char *Buffer,long Size)
{
SendData_1(CMD,Buffer,Size,0);                  //无Position方式发送数据
}

void __fastcall TSendFiles::SendData_1(AnsiString CMD,char *Buffer,long Size,long Position)
{
TSendFileData TempData;                             //临时数据缓冲
Application->ProcessMessages();
memset(&TempData,0,sizeof(TSendFileData));          //清除缓冲区

//**************************分析要发送的数据*********************************
TempData.Ver='1';
if (!(CMD=="FRLast"||CMD=="FSLast"))                //执行的不是"重发"命令
   {
   if (CMD=="FSCrea") TempData.Position=ReadFileSize;//建立文件命令借用Position传送文件长度
   if (CMD=="FSFile") TempData.Position=Position;   //传送文件时保存文件指针(当前Position已经读了Size字节)
   strcpy(TempData.FileFlage,CMD.c_str());          //保存命令码
   TempData.Size=Size;                              //保存数据长度
   memmove(&TempData.Data,Buffer,Size);             //把要发送的数据保存到临时数据中
   TempData.CRC=0;
   unsigned short CRC;
   CRC=CRC_16(&TempData.FileFlage[0],sizeof(TempData));//计算CRC校验码
   TempData.CRC=CRC;                                //保存CRC
   ErrorCount=0;                                    //错误计数器
   FSTimeOut=0;
   }
else                                                //执行"重发"命令
   {
   if (CMD=="FSLast")                               //发送方重发
       memmove(&TempData,&LastSendData,sizeof(TSendFileData));//把最后一次的发送方数据取出
   else
       memmove(&TempData,&LastReciveCMD,sizeof(LastReciveCMD));//把最后一次的接收方数据取出
   Size=TempData.Size;
   ErrorCount++;                                    //错误计数器+1
   if (ErrorCount>10)                               //重发超过10次
      {
        FSStatusBar->Panels->Items[1]->Text="传输错误,发送失败";
        return;
      }
   }
//***************准备发送******************************************************
   if (CMD.SubString(1,2)=="FS")                    //保存最后一次发送的数据
      {
       memmove(&LastSendData,&TempData,sizeof(TSendFileData));    //发送方数据
       FSTimer->Enabled=true;                              //启动超时定时计数器
      }
   else
      {
       memmove(&LastReciveCMD,&TempData,sizeof(LastReciveCMD));    //接受方响应数据
      }
   WriteToUDF(TempData.FileFlage,sizeof(TSendFileData)-1000+Size);  //发送数据包到UDP
}




//******************善后处理***********************
void __fastcall TSendFiles::FormDestroy(TObject *Sender)
{
delete ReadFile;
delete WriteFile;
delete [] WriteList;//删除文件块状态数据
ReadFile=NULL;
WriteFile=NULL;
}
//---------------------------------------------------------------------------


//***************发送UDP数据****************************
//此处为与主程序合并接口内容,奇怪的是如果用SendBuff发送,在2000下没问题,在9X下会出错
//所以这里用MyStream过渡了一下,改用SendStream发送。
//******************************************************
void __fastcall TSendFiles::WriteToUDF(char *Buffer,int Size)
{
NMUDP1->RemoteHost=RemoteIP->Text;
NMUDP1->RemotePort=RemotePort->Text.ToIntDef(6666);
TMemoryStream *MyStream =new TMemoryStream();
try
{
MyStream->WriteBuffer(Buffer,Size);
NMUDP1->SendStream(MyStream);
}
catch (...){}
delete MyStream;
}


//**************接收到的UDP数据******************************
//此处为与主程序的接口部分,判断FileFlag第一个字节为"F",调Proc_Send_F。
//***********************************************************
void __fastcall TSendFiles::NMUDP1DataReceived(TComponent *Sender,
      int NumberBytes, AnsiString FromIP, int Port)
{
TSendFileData RecivedData;
memset(&RecivedData,0,sizeof(TSendFileData));

NMUDP1->RemoteHost=FromIP;
RemoteIP->Text=FromIP;
NMUDP1->RemotePort=Port;
RemotePort->Text=IntToStr(Port);

NMUDP1->ReadBuffer(&RecivedData.FileFlage[0],8192,NumberBytes);//接受数据
AnsiString Flag;
Flag=RecivedData.FileFlage;             //数据包类型
if (Flag.SubString(1,1)=="F")           //文件传送类数据
  {
   if (RecivedData.Ver=='1') Proce_Send_F_1(RecivedData);       //1版处理文件传送类数据包
  }
}
//---------------------------------------------------------------------------


//********************文件传送类数据处理程序******************
void __fastcall TSendFiles::Proce_Send_F_1(TSendFileData FileData)
{
Application->ProcessMessages();
unsigned short CRC1,CRC2;               //以下计算CRC校验码
CRC1=FileData.CRC;                      //传送来的CRC
FileData.CRC=0;
CRC2=CRC_16(&FileData.FileFlage[0],sizeof(TSendFileData));//计算CRC
AnsiString CMD,FileName;                //命令码,文件名
CMD=FileData.FileFlage;                 //取出对方送来的命令码
div_t x=div(FileData.Position,1000);    //计算包编号Index
int Index=x.quot;
if (x.rem>0) Index++;

if (CRC1!=CRC2)                         //校验错误,重发
   {
    if (CMD=="FSFile")                  //如果发来的是文件数据包
       {
        FRError->Lines->Add(IntToStr(Index));//显示CRC错误的包编号
        SendData_1("FRCRC","",0,FileData.Position);//通知发送方重发CRC错误的包
       }
    else                                //不是文件数据包,则要求发送方重发最后一个包
       {
        if (CMD.SubString(1,2)=="FR")   //收到的是接收方发来的命令(目前程序是作为发送方)
           SendData_1("FSRepa","",0);   //发送:发送方方发出的"重发"命令
        else                            //收到的是发送方发来的命令(目前程序是作为接收方)
           SendData_1("FRRepa","",0);   //发送:接收方发出的"重发"命令
       }
    return;
   }
//***********************以下是CRC校验正确的包*********************
if (CMD=="FSFile")                      //如果是文件数据包
   {
    WriteList[Index]=true;              //置对应包正确标志
   }
if (CMD.SubString(1,2)=="FR")           //收到的是接收端返回的信息
     {
      if (CMD!="FRRate") FRCMDS->Lines->Add(CMD);
      FSTimer->Enabled=false;           //关闭发送超时定时计数器
      if (FRCMD!="FRRead" &&FRCMD!="FREnd" && FRCMD==CMD) return;//正在执行发送端命令,忽略重复的命令
      if (CMD!="FRRate") FRCMD=CMD;                        //保存当前命令
     }
else                                    //收到的是发送端发来的信息
     {
     if (!(FSCMD=="FSFile"&&CMD=="FSFile")) FSCMDS->Lines->Add(CMD);
     if (CMD!="FSFile" &&CMD!="FSStop" && FSCMD==CMD) return;//正在执行接收端命令
     FSCMD=CMD;                          //保存当前命令
     }


//********************以下是接收方命令处理程序***************************************
if (CMD=="FSName")                      //发送来的数据是文件名
   {
    FSCMDS->Lines->Clear();
    FSCMDS->Lines->Add(CMD);
    FileName=FileData.Data;             //取出文件名
    if (ReciveType->ItemIndex==2)       //拒绝接收任何文件
       {
        SendData_1("FRReje","",0);      //向发送方发出拒绝接收文件指令
        return;
       }
    if (ReciveType->ItemIndex==1)       //向用户提示接收文件
       {
        if (MessageDlg("对方发来"+FileName+",接收吗?",mtConfirmation,mbOKCancel,0)!=mrOk)//用户拒绝
           {
            if (FRCMD!="FSCanc") SendData_1("FRReje","",0);//在此之前没有收到Cancel则向发送方发出拒绝接收文件指令
            return;
           }
       }
    if (FRCMD=="FSCanc") return;           //在此之前收到Cancel
    if (FileExists(GetDir()+"\\"+FileName))//检查指定路径下有无重名文件
         SendData_1("FRExis",FileName.c_str(),FileName.Length());//有,发送重名信息
    else SendData_1("FRNot",FileName.c_str(),FileName.Length()); //无,发送无重名信息
    return;
   }
if (CMD=="FSCrea")                      //发送来的数据是建立文件命令
   {
    if (WriteFile!=NULL)
       {
        return;
       }
    FileName=FileData.Data;             //取出文件名

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -