文件传输协议使用户能在两个联网的计算机之间传输文件。FTP提供了一种允许客户端建立FTP控制连接并在两台FTP服务器间传输文件的机制。但在实际应用中FTP并不能完全满足要求,在一些特殊场合需要程序设计人员根据用户的要求自定义文件传输协议。
1 自定义文件传输协议
文件传输是指将文件从一台计算机上发送到另一台计算机上,传输的文件可以包括电子报表、声音、编译后的程序以及字处理程序的文档文件。
目前Internet上应用最广的文件传输协议是FTP(File Transfer Protocol)。FTP是定义如何在TCP/IP网络中进行文件传输的一个标准协议,采用Client/Server模式,由客户端发出连接请求,向服务器提交FTP命令,服务器接收到命令后,返回对命令的响应,并进行文件操作,完成后,向服务器发出解除连接请求,结束FTP 会话。
自定义文件传输协议通常情况下应该具备两大功能,即文件共享和远程文件管理功能。文件共享功能指该协议允许授权用户获取服务器指定目录的文件列表信息和下载文件。远程文件管理功能指该协议允许授权用户远程修改或删除服务器中的目录与文件和上传文件。此外,还可以根据实际需要添加其他功能。在网络协议的选择上,可以使用TCP/IP协议,也可以使用UDP协议等,或者同时使用多种网络协议。
2自定义文件传输协议的实现方法
在程序设计中实现对标准文件传输协议FTP的支持比较简单,而要支持自定义的文件传输协议则相对比较复杂。
2.1 应用程序必须提供相应的网络通讯功能,若采用UDP协议进行文件传输,代码如下。
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define WM_UDP_EVENT WM_USER + 100
WSADATA wsaData;
SOCKET m_hUdpSocket;
SOCKADDR_IN m_saUdpAddr;
WSAStartup(MAKEWORD(2, 2), &wsaData);
m_hUdpSocket = socket(AF_INET, SOCK_DGRAM, 0);
m_saUdpAddr.sin_family = AF_INET;
m_saUdpAddr.sin_port = htons(2005);
m_saUdpAddr.sin_addr.s_addr = INADDR_ANY;
bind(m_hUdpSocket, (LPSOCKADDR) &m_saUdpAddr, sizeof(m_saUdpAddr));
WSAAsyncSelect(m_hUdpSocket, hWnd, WM_UDP_EVENT, FD_READ);
2.2 应用程序需要根据自定义文件传输协议来解析并执行文件传输指令。指令可以由字符串组成,也可以是整型数据。使用整型数据定义文件传输指令(GET_FILE_LIST:获取文件列表信息;FILE_LIST_DATA:反馈文件列表信息)。
#define GET_FILE_LIST 0x00000100
#define FILE_LIST_DATA 0x00000101
struct COMMAND_HEAD {
char sIdentifier[2]; // 标识符
float fVersion; // 版本号
long lCommand; // 指令
};
struct FILE_LIST {
char szFileName[260]; // 文件名
DWORD nFileSizeHigh; // 文件长度高字节
DWORD nFileSizeLow; // 文件长度低字节
Char szTypeName[80]; // 文件类型
DWORD dwFileAttributes; // 文件属性
FILETIME ftLastWrite; // 修改时间
};
struct COMMAND_FILE_LIST {
COMMAND_HEAD CommandHead;
FILE_LIST flFileList;
};
LRESULT CFileTransferView::OnUdpEvent(WPARAM wParam, LPARAM lParam)
{
char szReceiveData[2048]; // 接收数据
CString strIP; // IP地址
u_short nPort; // 端口号
COMMAND_HEAD* pCommmandHead;
COMMAND_FILE_LIST* pCommandFileList;
switch (WSAGETSELECTEVENT(lParam))
{
case FD_READ:
// 获取数据、IP地址和端口号
……
pCommmandHead = (COMMAND_HEAD*) szReceiveData;
switch (pCommmandHead->lCommand)
{
case GET_FILE_LIST:
GetFileList(strIP, nPort, sShareFolder);
break;
case FILE_LIST_DATA:
pCommandFileList = (COMMAND_FILE_LIST*) pCommmandHead;
DisplayFileInfo(pCommandFileList->flFileList);
break;
}
}
return 0L;
}
BOOL CFileTransferView::GetFileList(CString sIP, u_short nPort, CString stRFolderName)
{
HANDLE hFind;
WIN32_FIND_DATA fdFindData;
COMMAND_FILE_LIST CommandFileList;
ZeroMemory(&CommandFileList, sizeof(COMMAND_FILE_LIST));
……
CommandFileList.CommandHead.lCommand = FILE_LIST_DATA;
hFind = FindFirstFile(strFolderName, &fdFindData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
if (strcmp(fdFindData.cFileName, "..") != 0 && strcmp(fdFindData.cFileName, ".") != 0)
{
strcpy(CommandFileList.flFileList.szFileName, fdFindData.cFileName);
CommandFileList.flFileList.dwFileAttributes = fdFindData.dwFileAttributes;
if((fdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
CommandFileList.flFileList.nFileSizeHigh = 0;
CommandFileList.flFileList.nFileSizeLow = 0;
}
else
{
CommandFileList.flFileList.nFileSizeHigh = fdFindData.nFileSizeHigh;
CommandFileList.flFileList.nFileSizeLow = fdFindData.nFileSizeLow;
}
CommandFileList.flFileList.ftLastWrite = fdFindData.ftLastWriteTime;
if (!Send(sIP, nPort, (char*) &CommandFileList, sizeof(COMMAND_FILE_LIST)))
return FALSE;
}
} while (FindNextFile(hFind, &fdFindData));
}
FindClose(hFind);
return TRUE;
}
2.3 关闭套接字。
if (m_hUdpSocket != INVALID_SOCKET)
closesocket(m_hUdpSocket);
3 结语
FTP依赖于TCP/IP协议,同时也受限于TCP/IP协议。在一些特殊场合,可能需要利用UDP协议来进行文件传输,或者需要Internet上实现基于P2P(Peer-to-Peer)技术的文件共享功能,因此需要根据需要自定义文件传输协议。自定义文件传输协议具有很大的灵活性,可以满足不同场合的用户需要。