📄 comfiledlg.cpp
字号:
AddLog(" 正在准备发送文件... \r\n");
// 发送文件大小
int nFileSize = file.GetLength();
if(!pSerial->SendFileSize(nFileSize))
{
AddLog(" 发送文件大小失败!\r\n ");
return FALSE;
}
//////////////////////////////////////////////////
// 发送文件数据
char Buffer[1024]; // 数据缓冲区
int nRead; // 从文件中每次读取的字节数
DWORD dwTotalSendLen = 0; // 总共发送的字节数
// 初始化序列号为0
pSerial->m_sequence = 0;
AddLog(" 正在发送文件数据... \r\n ");
while(TRUE)
{
// 从文件中读取数据到缓冲区
nRead = file.Read(Buffer, 1024);
if(nRead <= 0)
{
break;
}
// 发送缓冲区中的数据
int nLeft = nRead; // 剩余的字节数
int nSendLen; // 要发送的字节数
while(nLeft > 0)
{
// 发送一个贞,如果发送失败,重试5次
nSendLen = nLeft > FRAME_SIZE ? FRAME_SIZE : nLeft;
n=0;
while(!pSerial->SendFileData(&Buffer[nRead-nLeft], nSendLen) && n++<5)
{
if(!pSerial->m_pSerial->IsOpen()) // 检查是否用户故意中止
{
AddLog(" 发送文件出错,用户关闭串口! \r\n");
return FALSE;
}
str.Format(" 帧重发 %d 次 \r\n", n);
AddLog(str);
}
if(n>=5)
{
m_Status.SetWindowText(" 发送文件出错!!!");
return FALSE;
}
// 帧发送成功,更新状态变量
nLeft -= nSendLen;
dwTotalSendLen += nSendLen;
// 向用户显示当前文件发送进度
str.Format(" 已发送:%d KB,剩余:%d KB \r\n",
dwTotalSendLen/1024, (nFileSize - dwTotalSendLen)/1024);
m_Status.SetWindowText(str);
}
}
///////////////////////////////////////////////////////
// 发送结束标志
BYTE command = SendEOF();
if(command != 0) // 出错?
{
switch(command) // 检查出错原因
{
case SERIAL_TRANSFAILED:
{
m_Status.SetWindowText(" 文件传输完毕,但是有错误! \r\n");
AddLog(" 文件传输完毕,但是有错误! \r\n");
}
break;
}
return FALSE;
}
// 文件发送完成,向用户显示用时
DWORD dwEsp = ::GetTickCount() - dwTick;
str.Format(" 文件发送成功完成。[%d KB] 用时: %d 秒", nFileSize/1000, dwEsp/1000);
AddLog(str);
return TRUE;
}
DWORD CComFileDlg::ServerProc() // 服务线程,一直在后台运行
{
CSerialFrame *pFrame; // 帧指针
CSCSerial *m_pServer = m_pComFile; // CSCSerial对象指针(作为服务器用)
// 状态初始化为IDLE
m_pServer->m_nStatus = STATUS_IDLE;
// 禁止线程退出
m_bThreadExit = FALSE;
// 进入无限循环,处理从COM口接收到的数据
int n=0; // 帧重发次数
while(TRUE)
{
// 等待数据的到来
while((pFrame = m_pServer->ReadFrame()) == NULL)
{
if(m_bThreadExit || !m_com.IsOpen())
{
AddLog(" 用户请求线程退出 \r\n");
return 0;
}
// 检查是否需要发送文件
if(m_bNeedSend)
{
AddLog(" 正在准备发送文件... \r\n");
m_pServer->m_nStatus = STATUS_IDLE;
if(Connect())
{
AddLog(" 连接成功 \r\n");
if(!SendFile(m_SendFile, m_pServer))
{
AddLog(" 发送文件失败\r\n");
m_Status.SetWindowText(" 发送文件失败\r\n");
}
else
{
AddLog(" 发送文件成功 \r\n");
m_Status.SetWindowText(" 发送文件成功 \r\n");
}
}
m_pServer->m_nStatus = STATUS_IDLE;
m_bNeedSend = FALSE;
if(m_com.IsOpen())
m_Send.EnableWindow();
}
}
// 检查贞大小
if(pFrame->uDataLen > FRAME_SIZE)
{
AddLog(" CServerDlg::ThreadProc() 帧传输出错!\r\n");
m_com.Purge();
continue;
}
// 传输其他字节
if(pFrame->uDataLen > 0)
{
if(!m_com.ReadData(pFrame + 1, pFrame->uDataLen, 500))
{
if(m_bThreadExit || !m_com.IsOpen())
{
AddLog(" 用户请求线程退出 \r\n");
return 0;
}
m_com.Purge();
AddLog(" CServerDlg::ThreadProc() 读取数据超时 \r\n");
continue;
}
}
// 检查效验位
int nChecksum = pFrame->uChecksum;
pFrame->uChecksum = 0;
if(nChecksum != checksum((USHORT*)pFrame, sizeof(CSerialFrame) + pFrame->uDataLen))
{
AddLog(" CServerDlg::ThreadProc() 数据效验出错 请求重新传送\r\n");
// 请求重发
m_pServer->SendRetry();
continue;
}
///////////////////////////////////////////////
// 处理命令
switch(pFrame->command)
{
case SERIAL_CONNECT: // 连接过程
{
if(m_pServer->m_nStatus == STATUS_IDLE || m_pServer->m_nStatus == STATUS_CONNECTED)
{
m_pServer->SendAck();
m_pServer->m_sequence = 0;
m_pServer->m_nStatus = STATUS_CONNECTED;
AddLog(" 接收到新连接,正准备接收文件... \r\n");
m_Status.SetWindowText(" 接收到新连接,正准备接收文件... \r\n");
}
else
{
m_pServer->SendInit();
m_pServer->m_nStatus = STATUS_IDLE;
AddLog(" 接收到非法连接,要求初始化 \r\n");
}
}
break;
case SERIAL_INIT: // 对方请求重新初始化
{
AddLog(" 对方要求重新初始化 \r\n ");
m_pServer->SendAck();
m_pServer->m_nStatus = STATUS_IDLE;
}
break;
case SERIAL_SIZE: // 对方发送文件大小信息,接收到此命令就要进行文件传输
{
if(m_pServer->m_nStatus == STATUS_CONNECTED)
{
m_dwFileLen = *(DWORD*)(pFrame+1);
if(m_dwFileLen > 200*1024*1024)
{
m_pServer->SendCommand(SERIAL_TOOBIG);
AddLog(" 文件太大,拒绝接收(应小于200MB) \r\n");
continue;
}
// 为文件数据申请内存空间
m_pData = new BYTE[m_dwFileLen];
if(m_pData == NULL)
{
m_pServer->SendCommand(SERIAL_SYSFAILED);
AddLog(" 内存不足!传输失败 \r\n");
continue;
}
m_pServer->SendAck();
m_dwRecvLen = 0;
m_pServer->m_nStatus = STATUS_TRANSFERING;
}
else
{
m_pServer->SendInit();
AddLog(" 接收到非法命令,要求初始化 \r\n");
}
}
break;
case SERIAL_DATA: // 读数据
{
if(m_pServer->m_nStatus != STATUS_TRANSFERING)
{
m_pServer->SendInit();
AddLog(" 接收到非法命令,要求初始化 \r\n");
continue;
}
// 定位实际数据
char *psz = (char*)(pFrame+1);
if(pFrame->sequence == m_pServer->m_sequence)
{
m_pServer->m_sequence++;
if(m_pData == NULL) // 检查指针是否有效
{
AddLog(" 程序问题,没有准备好传输 \r\n");
m_pServer->SendInit();
continue;
}
if(!m_pServer->SendAck())
{
m_pServer->SendInit();
m_Status.SetWindowText(" 用户关闭串口,传输非法终止!! ");
AddLog(" 用户关闭串口,传输非法终止!! ");
delete[] m_pData;
m_pData = NULL;
m_dwRecvLen = 0;
m_dwFileLen = 0;
continue;
}
// 接收数据
memcpy(&m_pData[m_dwRecvLen], pFrame+1, pFrame->uDataLen);
m_dwRecvLen += pFrame->uDataLen;
// 显示文件传输进度
CString str;
str.Format("已经接收 【%d KB】,剩余【%d KB】",
m_dwRecvLen/1024, (m_dwFileLen-m_dwRecvLen)/1024);
m_Status.SetWindowText(str);
}
else if(pFrame->sequence < m_pServer->m_sequence) // 客户重发的贞,忽略
{
m_pServer->SendAck();
AddLog(" 对方等待时间过短,收到重发贞 \r\n");
continue;
}
else // 序列号错误?
{
AddLog(" 数据序列号出错 要求重新初始化 \r\n");
// 重新初始化
m_pServer->SendInit();
continue;
}
}
break;
case SERIAL_EOF: // 接收文件结束,开始打印
{
if(m_pServer->m_nStatus == STATUS_TRANSFERING)
{
if(m_dwRecvLen == m_dwFileLen)
{
m_pServer->SendAck();
// 处理接收到的文件数据
OnRecvCmp(m_pData, m_dwFileLen);
delete m_pData;
m_pData = NULL;
m_dwFileLen = 0;
AddLog(" 文件传输成功完成!\r\n");
}
else
{
// 请求对方重新传输
m_pServer->SendCommand(SERIAL_TRANSFAILED);
m_Status.SetWindowText(" 文件传输完成,但是有错误!\r\n");
AddLog(" 文件传输出错!\r\n");
}
m_pServer->m_nStatus = STATUS_IDLE;
}
else
{
AddLog(" 接收到非法命令,要求初始化 \r\n");
m_pServer->SendInit();
}
}
break;
default:
m_Status.SetWindowText(" 接收到非法命令 \r\n");
AddLog(" 接收到非法命令 \r\n");
m_pServer->m_nStatus = STATUS_IDLE;
break;;
}
}
return 0;
}
void CComFileDlg::OnRecvCmp(PBYTE pData, DWORD dwFileLen) // 文件接收完毕
{
CFileDialog dlg(FALSE);
if(dlg.DoModal() == IDCANCEL)
{
return;
}
// 将数据保存到文件
CFile file;
if(!file.Open(dlg.GetPathName(), CFile::modeCreate|CFile::modeWrite))
{
m_Status.SetWindowText(" 创建文件失败!");
return;
}
file.WriteHuge(pData, dwFileLen);
file.Close();
}
//-----------------------------公共函数--------------------------------//
BYTE CComFileDlg::SendConnect() // 发送连接命令
{
// 发送
CSerialFrame *pFrame;
if(!m_pComFile->SendCommand(SERIAL_CONNECT))
{
AddLog(" 连接服务器失败,用户关闭串口! \r\n ");
return 0xff;
}
// 等待结果
pFrame = m_pComFile->ReadData();
if(pFrame == NULL)
{
AddLog(" 连接服务器失败,对方没有响应! \r\n ");
return 0xff;
}
if(pFrame->command == SERIAL_ACK)
{
m_pComFile->m_nStatus = STATUS_CONNECTED;
AddLog(" 成功连接到服务器 \r\n");
return 0;
}
else
return pFrame->command;
}
BYTE CComFileDlg::SendEOF() // 发送文件结束命令
{
// 发送
CSerialFrame *pFrame;
if(!m_pComFile->SendCommand(SERIAL_EOF))
{
AddLog(" 用户关闭端口,文件发送失败! \r\n ");
return 0xff;
}
// 等待结果
pFrame = m_pComFile->ReadData();
if(pFrame == NULL)
{
AddLog(" 对方没有响应,文件发送失败! \r\n");
return 0xff;
}
if(pFrame->command == SERIAL_ACK)
{
m_pComFile->m_nStatus = STATUS_IDLE;
AddLog(" 文件发送成功完成 \r\n");
return 0;
}
else
return pFrame->command;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -