📄 sendfile_cpp.cpp
字号:
//---------------------------------------------------------------------------
#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 + -