关于利用Tcp库来实现文件传输

来源:互联网 发布:淘宝互刷收藏软件 编辑:程序博客网 时间:2024/05/30 02:24

文件传输主要是学习文件处理的windows API函数、数据结构操作和 string操作。

首先应用库来建立一个服务器和一个客户端,都是单线程。

服务器说明:建立一个结构体tTransFile

struct tTransFile{    int nLen;    int nIdx;    char szFileName[255];    UINT32 uFileSize;    char* GetData()    {        return  (char*) (this + 1);    }}

我建立的是一个比较简单的文件传输,要传入一个存储该文件的路径,然后分析这个路径,需要应用API函数FindFirstFile

HANDLE FindFirstFile( LPCTSTR lpFileName, //文件或文件夹路经r LPWIN32_FIND_DATA lpFindFileData );BOOL FindNextFile( HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData );BOOL FindClose(HANDLE hFindFile );

 

typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; //文件属性 FILETIME ftCreationTime; // 文件创建时间 FILETIME ftLastAccessTime; // 文件最后一次访问时间 FILETIME ftLastWriteTime; // 文件最后一次修改时间 DWORD nFileSizeHigh; // 文件长度高32位 DWORD nFileSizeLow; // 文件长度低32位 DWORD dwReserved0; // 系统保留 DWORD dwReserved1; // 系统保留 TCHAR cFileName[ MAX_PATH ]; // 长文件名 TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
lpFileNameString,欲搜索的文件名。参数可如下:
c:\Windows\*.* //在c:\Windows目录中查找所有文件 
c:\Windows\System32\*.dll //在c:\Windows\System32目录中查找所有dll文件 
c:\Windows\System.ini ;在c:\Windows目录中查找System.ini文件 
c:\Windows\a???.* // 在c:\Windows目录中查找所有以a开头的文件名长度.为4个字符的文件 
Test.dat //在当前目录查找Test.dat文件
 *.* //在当前目录查找所有文件



也可以使用下面这个方法获取文件信息:

BOOL GetFileInformationByHandle(HANDLE hFile, // 文件的句柄 LPBY_HANDLE_FILE_INFORMATION lpFileInformation );


 

typedef struct _BY_HANDLE_FILE_INFORMATION {  DWORD dwFileAttributes;  FILETIME ftCreationTime;  FILETIME ftLastAccessTime;  FILETIME ftLastWriteTime;  DWORD dwVolumeSerialNumber; // 文件所在的磁盘的序列号 DWORD nFileSizeHigh;  DWORD nFileSizeLow;  DWORD nNumberOfLinks; //链接的数目 DWORD nFileIndexHigh;  DWORD nFileIndexLow; } BY_HANDLE_FILE_INFORMATION;

我主要应用的是FindFirstFile,WIN32_Find_DATA 应用里面的cFileName,然后获得HANDLE后就可以接着查询应用FINDNXETFILE,里面应用的结构体相同,也就是同样我们要取的都是文件的name,当然第一次和第二次取出来的都是”。“,”。。“,这是文件的两级目录,然后才能取到第一个文件的名称,然后一直循环取FINDNEXTFILE,当然是成功的情况下,如果失败返回INVALID_HANDLE_VALID。我在File_Server类中,还建立一个list<string>安放取到的文件名称。

为处理list<string>我还建立一个iterator it,用他来取用队列中的string字符串。下面就应该是接到信息然后分析这个信息操作。

这个信息就是协议,也是结构体。我收到的可能不是协议类型,如此我们强制转换该数据,因为这就是一个下载服务器(当然我是这么认为的,内网中可用),主要监听的就是要下载第几个文件,知道nIdx后,就可以操作知道it的指向队列中第几个字符串,然后通过FindAndOpenFile函数(这个是我自己起的名不是API),FindAndOpenFile主要是字符串操作把该文件的路径拼完全,然后用此路径调用API函数CreateFile获取文件句柄hFile,用hFile先调用GetFileSize,获取文件的大小,然后再掉SetFilePointor,确定文件每次开始读取都从文件开始处开始。

回信息操作:1、获取文件大小赋值给结构体中uFileSize

                        2、获取文件名称复制给szFileName

                        3、分析读取信息ReadFile中GetLeng,把第一读取的大小记录下来。

                        4、填充整个数据的大小nLen,他的大小包括第一次读取到的文件的大小+结构体的大小。

                        5、这个最重要差点忘了,就是可能数据比较到,只应用结构体操作可能他的存放空间不够,也就是在栈上操作空间不够,如此我们需要在堆上操作这个要发送出去的数据。new char[MAX_SIZE_SEND],然后应用强制转换等等操作,就可以把这个数据发出去,(重点是send中数据的长度,不可以用sizeof+指针,要用nLen的长度).

                       6、后面的操作就是在文件大小和读取大小之和比较的条件下,开始不断的循环发生数据。直到完成发送,完成后,记得把it还原。关闭HANDLE,回收堆内存。

                       7、忘啦一条,就是关闭HANDLE,应用完FindNextFile后要关闭HANDLE。

客户端操作:

这个比较简单,1、获取文件存储的地址

                            2、建立和服务器连接的条件端口和IP

                            3、建立连接后,发送信息,就是结构体,也是协议,主要填写的是nIdx,就是要下那个文件。发送这个数据操作和服务器中5相同的操作。发送完后要回收堆内存。                           

                            4、接收信息,首先要分析这个数据,分析协议,取出文件大小、文件名称、还有数据和结构体分离。

                            5、根据结构中的文件名称和1的操作通过字符串操作CreateFile,并且记录下第一次收到的数据的大小。

                            6、开始应用WriteFile写入文件,两方面来保证收到的数据完成,一是recv,二是收到的数据和文件大小比较,如果相等就写入完成。

                            7、处理关闭不需要的HANDLE,SOCKET和各种堆内存。

                           


 

原创粉丝点击