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

📄 excute.cpp

📁 tftp功能服务器及客户端的实现
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// excute.cpp: implementation of the Cexcute class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TftpSrv.h"
#include "excute.h"
#include <stdio.h>
#include <string.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Cexcute::Cexcute(u_short pcode,char *fileandmode,SOCKADDR_IN RcvAddr,HWND hwnd)
{	
	this->pcode=pcode;
	this->fileandmode=fileandmode;
	this->RcvAddr=RcvAddr; 
	this->tftpHwnd = hwnd;
	this->PortCount = (u_short)6006;
	this->TotalTime = 0;
	this->RcvPort = htons(RcvAddr.sin_port);
	len = sizeof(SOCKADDR);
	TVal.tv_sec = 5;
	TVal.tv_usec =0;
	Init();

	char *szLogPath = "D:\\TftpSrvLog";
	CreateDirectory(szLogPath,NULL); 
	 
	//list[200] 设置 LOg 文件路径,log文件名由客户端主机ip及请求文件和请求方式组成
	char list[200];
	if(pcode == RRQ)
		sprintf(list,"D:\\TftpSrvLog\\%s.RRQ %s.log",inet_ntoa(RcvAddr.sin_addr),fileandmode);
	else if(pcode == WRQ)
		sprintf(list,"D:\\TftpSrvLog\\%s.WRQ %s.log",inet_ntoa(RcvAddr.sin_addr),fileandmode);
	//打开创建 Log 文件
	if(pcode == RRQ || pcode == WRQ)
		stream = fopen(list,"a+");
	
	if(stream == NULL)
	{
		AfxMessageBox("初始化log文件失败");
		fclose( stream );
	}	
	//写 log 头部
	if(pcode == RRQ)
	{
		sprintf(list,"-------------------------RRQ %s--------------------------\n",fileandmode);
		fwrite(list,1,strlen(list),stream);
	}
	else if(pcode == WRQ)
		{
		sprintf(list,"-------------------------WRQ %s---------------------------\n",fileandmode);
		fwrite(list,1,strlen(list),stream);
	}
	SendMessage();			
}

Cexcute::~Cexcute()
{
	
}
//Init 新创建进程套接字初始化
BOOL Cexcute::Init()
{
	
	 SrvSocket = socket(AF_INET,SOCK_DGRAM,0);
	 if(SrvSocket == INVALID_SOCKET)
	 {
		AfxMessageBox("socket erro");
		return FALSE;
	 }
	 
	 SrvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	 SrvAddr.sin_family = AF_INET;
	 SrvAddr.sin_port = htons(PortCount++);
	 
	if(INVALID_SOCKET ==(bind(SrvSocket,(SOCKADDR*)&SrvAddr,sizeof(SrvAddr))))
	{
		return Init();
	}

	return TRUE;
}

//SendMessage 收发文件函数
void Cexcute::SendMessage()
{
	StartTime = GetCurrentTime(); 
	TotalTime = StartTime.GetHour();
	timeFormat = StartTime.Format("%H:%M:%S");
	size_t nBytesRcv = 0;
	size_t TotalBytes = 0;
	u_short		 b = 0;
	int timeout    = 0;
	int Repeat = 0;
	int OpcodeErr  = 1;

	switch(pcode) 
	{
	//========================下载文件请求 RRQ==================	
	case RRQ :
		
		sprintf(strDisplay,"%s : [%s%d] 请求下载文件 %s,连接成功!\n",
			timeFormat,inet_ntoa(RcvAddr.sin_addr),RcvPort,fileandmode);
		::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
		fwrite(strDisplay,1,strlen(strDisplay),stream);

		DBuf.pcode = htons(DAT);
			
		if((pFile = fopen(fileandmode,"r"))==NULL)
		{	//请求文件不存在,中止服务
			SendErrors(1);
			
			timeNow=CTime::GetCurrentTime(); 
			timeFormat=timeNow.Format("%H:%M:%S");
			sprintf(strDisplay,"%s : [RRQ %s] 服务器找不到请求文件,停止!\n",
					timeFormat,fileandmode);
			::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
			fwrite(strDisplay,1,strlen(strDisplay),stream);
			fclose(stream);
			return ;
		}	
		fclose(pFile);
		
		CFile *pCFile;
		pCFile=new CFile((LPCTSTR)fileandmode, CFile::modeRead);
	
		size_t nBytesRead;
		size_t SendBuf;
		while(1)//发送数据
		{
			
			memset(DBuf.buf,0,512);
			//读文件数据,默认二进制格式
			nBytesRead = pCFile->Read(DBuf.buf, 512);
			TotalBytes += nBytesRead;
		
			DBuf.block = htons(++b); //设置网络字节序的数据包序列号

			fd_set SockSet;
			
			SendBuf = nBytesRead + 4;//发送数据的总长度,由4字节的block
									//和opcode和实际的数据组成
			timeNow=CTime::GetCurrentTime(); 
			timeFormat=timeNow.Format("%H:%M:%S");
			sprintf(strDisplay,"%s : 给   [%s:%d] 发送第 %d 号 DATA  %d Bytes\n",
					timeFormat,inet_ntoa(RcvAddr.sin_addr),RcvPort,b,nBytesRead);
			
			::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
			fwrite(strDisplay,1,strlen(strDisplay),stream);

			while(1)//超时循环 
			{	
				sendto(SrvSocket,(char*)&DBuf,SendBuf,0,
					(SOCKADDR*)&RcvAddr,len);
				
				FD_ZERO(&SockSet);
				FD_SET(SrvSocket,&SockSet);
				if(select(SrvSocket,&SockSet,NULL,NULL,&TVal))
				{	//select 函数限制套接字的 recvfrom 阻塞时间,此处为 5 s				
					recvfrom(SrvSocket,(char*)&ABuf,sizeof(AckBuf),
						0,(SOCKADDR*)&RcvAddr,&len);
					
					if(ntohs(ABuf.pcode) != ACK || ntohs(ABuf.block) != b)
					{
						//收到不正确包的处理:重发报文再次接受
						Repeat++;
						timeNow=CTime::GetCurrentTime(); 
						timeFormat=timeNow.Format("%H:%M:%S");

						if(Repeat == 5)
						{	//重复收取不正确包 5 次,则中止服务
							timeNow=CTime::GetCurrentTime(); 
							timeFormat=timeNow.Format("%H:%M:%S");
							sprintf(strDisplay,"%s : 给   [%s:%d] 重发第 %d 号 DATA  第 %d 次,中止服务.\n",
							timeFormat, inet_ntoa(RcvAddr.sin_addr),RcvPort,b,Repeat);
							::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
							fwrite(strDisplay,1,strlen(strDisplay),stream);

							Repeat = 0;
							delete pCFile;
							return;
						}

						sprintf(strDisplay,"%s : 给   [%s:%d] 重发第 %d 号 DATA  第 %d 次\n",
							timeFormat, inet_ntoa(RcvAddr.sin_addr),RcvPort,b,Repeat);
						::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
						fwrite(strDisplay,1,strlen(strDisplay),stream);
						
						continue;
					}
					else {
						//收到正确的 ACK 处理
						timeNow=CTime::GetCurrentTime(); 
						timeFormat=timeNow.Format("%H:%M:%S");
						sprintf(strDisplay,"%s : 收到 [%s:%d] 第     %d 号 ACK.\n",
							timeFormat,inet_ntoa(RcvAddr.sin_addr),RcvPort,b);
						::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
						fwrite(strDisplay,1,strlen(strDisplay),stream);

						if(nBytesRead<512)
						{	
							//发送的数据包为最后一个,传送完成处理
							timeNow=CTime::GetCurrentTime(); 

							pCFile->Close();

							TotalTime -= timeNow.GetHour();
							if(TotalTime <= 0)
								TotalTime = TotalTime * 60;//传文件时间不得超过24小时,否则检查不出正确耗时
							else
								TotalTime = 24 * 60;
							TotalTime += timeNow.GetMinute() - StartTime.GetMinute();
							TotalTime = TotalTime * 60;

							TotalTime += timeNow.GetSecond() - StartTime.GetSecond();

							if(TotalTime == 0)
								TotalTime = 1;
							
							sprintf(strDisplay,"发送%s完成[%s:%d]: %ld Bytes,时间: %d s, %d Bytes/s\n",fileandmode,
								inet_ntoa(RcvAddr.sin_addr),RcvPort,TotalBytes,TotalTime,u_int(TotalBytes/TotalTime));
							::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
							fwrite(strDisplay,1,strlen(strDisplay),stream);
							delete pCFile;
							fclose(stream);
							return;
						}
						break;
					}
				}
				else//if select
				{
					//select 超时处理
					if(5 == timeout) 
					{
						//连续超时 5 次,中止服务
						timeNow=CTime::GetCurrentTime(); 
						sprintf(strDisplay,"%s : 等待 [%s:%d] 第    %d 号 ACK 第 %d 次超时,中止服务!\n",
							timeFormat, inet_ntoa(RcvAddr.sin_addr),RcvPort,b,timeout);
						::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
						fwrite(strDisplay,1,strlen(strDisplay),stream);
						timeout = 0;
						delete pCFile;
						return;
					}
					timeNow=CTime::GetCurrentTime(); 
					sprintf(strDisplay,"%s : 等待 [%s:%d] 第    %d 号 ACK 第 %d 次超时!\n",
							timeFormat, inet_ntoa(RcvAddr.sin_addr),RcvPort,b,++timeout);
					::SendMessage(tftpHwnd,WM_DATADISPLAY,0,(LPARAM)strDisplay);
					fwrite(strDisplay,1,strlen(strDisplay),stream);
					memset((void*)&ABuf,0,sizeof(ABuf));
				}
			}//if select	
		}//while(1)
		break;

		//============================上传文件请求 WRQ==================
	case WRQ :

		//提示连接成功
		sprintf(strDisplay,"%s [%s:%d]请求上载文件 %s,连接成功!\n",

⌨️ 快捷键说明

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