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

📄 comfiledlg.cpp

📁 VC网络程序设计实例导航配套代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	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 + -