您的位置:首页 > 编程语言 > PHP开发

VC FTP服务器程序分析(四)

2016-01-25 10:49 671 查看
  下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。

  1、OnAccept 数据tcp服务器被连接的虚函数,由框架调用。

void CDataSocket::OnAccept(int nErrorCode)
{
// Accept the connection using a temp CSocket object.
CAsyncSocket tmpSocket;
Accept(tmpSocket);

SOCKET socket = tmpSocket.Detach();
Close();

Attach(socket);

m_bConnected = TRUE;

CAsyncSocket::OnAccept(nErrorCode);
}


  第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。

  2、OnReceive 数据接收处理函数

int CDataSocket::Receive()
{
TRACE("OnReceive\n");
int nRead = 0;

if (m_pControlSocket->m_nStatus == STATUS_UPLOAD)
{
if (m_File.m_hFile == NULL)
return 0;

byte data[PACKET_SIZE];
nRead = CAsyncSocket::Receive(data, PACKET_SIZE);

switch(nRead)
{
case 0:
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
// tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
break;
}
case SOCKET_ERROR:
{
if (GetLastError() != WSAEWOULDBLOCK)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
}
break;
}
default:
{
TRY
{
m_File.Write(data, nRead);
}
CATCH_ALL(e)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pControlSocket->SendResponse("450 Can't access file.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
return 0;
}
END_CATCH_ALL;
break;
}
}
}
return nRead;
}


  如果处于上传状态,那么将接收到的数据写入文件。

  3、PreSendFile 与发送文件有关的函数

BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
{
// close file if it's already open
if (m_File.m_hFile != NULL)
{
m_File.Close();
}

// open source file
if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
{
return FALSE;
}
m_nTotalBytesSend = m_File.GetLength();

if (m_pControlSocket->m_dwRestartOffset < m_nTotalBytesSend)
{
m_nTotalBytesTransfered = m_pControlSocket->m_dwRestartOffset;
}
else
{
m_nTotalBytesTransfered = 0;
}
return TRUE;
}


 初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。

 4、 SendFile函数 调用PrepareSendFile,调用OnSend发送文件。

void CDataSocket::SendFile(LPCTSTR lpszFilename)
{
if (!PrepareSendFile(lpszFilename))
{
// change status
m_pControlSocket->m_nStatus = STATUS_IDLE;

m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");

// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
return;
}
OnSend(0);
}


 5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。

 6、OnSend 主要区分了list命令的情况和download的情况。

void CDataSocket::OnSend(int nErrorCode)
{
CAsyncSocket::OnSend(nErrorCode);
switch(m_pControlSocket->m_nStatus)
{
case STATUS_LIST:
{
while (m_nTotalBytesTransfered < m_nTotalBytesSend)
{
DWORD dwRead;
int dwBytes;

CString strDataBlock;

dwRead = m_strData.GetLength();

if (dwRead <= PACKET_SIZE)
{
strDataBlock = m_strData;
}
else
{
strDataBlock = m_strData.Left(PACKET_SIZE);
dwRead = strDataBlock.GetLength();
}

if ((dwBytes = Send(strDataBlock, dwRead)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
Sleep(0);
return;
}
else
{
TCHAR szError[256];
wsprintf(szError, "Server Socket failed to send: %d", GetLastError());

// close the data connection.
Close();

m_nTotalBytesSend = 0;
m_nTotalBytesTransfered = 0;

// change status
m_pControlSocket->m_nStatus = STATUS_IDLE;

m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");

// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
}
}
else
{
m_nTotalBytesTransfered += dwBytes;
m_strData = m_strData.Mid(dwBytes);
}
}
if (m_nTotalBytesTransfered == m_nTotalBytesSend)
{
// close the data connection.
Close();

m_nTotalBytesSend = 0;
m_nTotalBytesTransfered = 0;

// change status
m_pControlSocket->m_nStatus = STATUS_IDLE;

// tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
}
break;
}
case STATUS_DOWNLOAD:
{
while (m_nTotalBytesTransfered < m_nTotalBytesSend)
{
// allocate space to store data
byte data[PACKET_SIZE];

m_File.Seek(m_nTotalBytesTransfered, CFile::begin);

DWORD dwRead = m_File.Read(data, PACKET_SIZE);

int dwBytes;

if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
Sleep(0);
break;
}
else
{
TCHAR szError[256];
wsprintf(szError, "Server Socket failed to send: %d", GetLastError());

// close file.
m_File.Close();
m_File.m_hFile = NULL;

// close the data connection.
Close();

m_nTotalBytesSend = 0;
m_nTotalBytesTransfered = 0;

// change status
m_pControlSocket->m_nStatus = STATUS_IDLE;

m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");

// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
}
}
else
{
m_nTotalBytesTransfered += dwBytes;
}
}
if (m_nTotalBytesTransfered == m_nTotalBytesSend)
{
// close file.
m_File.Close();
m_File.m_hFile = NULL;

// close the data connection.
Close();

m_nTotalBytesSend = 0;
m_nTotalBytesTransfered = 0;

// change status
m_pControlSocket->m_nStatus = STATUS_IDLE;

// tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
}
break;
}
}
}


  7、OnConnect函数 tcp连接成功时被框架调用的虚函数。

  8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。

  9、

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: