使用c++实现一个FTP客户端(三)
接上篇:http://www.cnblogs.com/jzincnblogs/p/5217688.html,这篇主要记录编程过程中需要注意的地方以及遇到的一些问题及解决方法。
一、gethostbyname(),inet_ntoa()等函数已经过时
使用上面两个函数时编译器会报错并提示函数已经是过时的了(obsolete),应该用getaddrinfo()与InetNtop()代替,这两个函数都是协议无关的,同时支持IPv4和IPv6,下面是一个使用例子:
string GetIPAddress(int af)
{
char host_name[IP_SIZE];
char buf_ip[IP_SIZE];
//
addrinfo hints;
memset(&hints, , sizeof(addrinfo));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//
addrinfo *result = nullptr;
//获取主机名字
int ret_val = ::gethostname(host_name, IP_SIZE);
if (ret_val == SOCKET_ERROR)
{
cerr << "Failed to get host name!\n";
return "";
}
//通过主机名字获取ip地址
ret_val = ::getaddrinfo(host_name, nullptr, &hints, &result);
if (ret_val != )
{
cerr << "Failed tp get host by name!\n";
return "";
}
SOCKADDR_IN *addr = (SOCKADDR_IN*)result->ai_addr;
::InetNtop(af, &addr->sin_addr, buf_ip, IP_SIZE);
//释放地址资源
::freeaddrinfo(result);
return (string)buf_ip;
}
关于两个函数的典型用法可以参考MSDN:https://msdn.microsoft.com/en-us/library/ms738520(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/cc805843(v=vs.85).aspx
二、换行符的问题
c++中如果输出时需要换行可以使用\n,但需要注意的是,在windows中回车换行表示为\r\n,而linux中表示为\n,而这也是FTP协议中二进制模式与ASCII模式的区别之一:ASCII模式会对文件进行转换,将换行符转换为客户端系统的表示方法,而二进制模式则不对文件进行改动。所以在windows环境下,FTP客户端与服务器交互过程中,客户端发送命令时要以\r\n结尾,而接收服务器的多行数据时每行数据的换行符均为\r\n。
三、被动模式
在FTP客户端与服务器进行数据传输时,一般使用被动模式,而客户端与服务器的数据连接在每次传输完成后都会关闭,这意味着每次客户端与服务器传输数据前都要先建立数据连接,也就意味着每次都要重新进入被动模式。通过发送PASV命令可以请求进入被动模式,若进入成功,服务器返回一条形如 227 Entering Passive Mode (a,b,c,d,e,f). 的消息,其中a.b.c.d表示服务器的IP地址,通过e,f可计算得到客户端应连接的服务器端口号,计算公式为:端口号=e*256 + f。
四、断点续传
当客户端下载文件过程因种种原因中断后,下次启动下载时就要用到断点续传,避免重新下载。
断点续传的实现步骤如下:
1.调用Windows API函数CreateFile()打开文件,然后使用GetFileSize()获取已下载的字节数。
2.从服务器中获取目标文件的字节数,进行比较。
3.断点续传的开始位置为已下载的字节数加1。
4.发送命令“REST offset\r\n”,其中offset为计算出来的文件偏移量。
5.若服务器响应成功,则发送命令“RETR 文件名\r\n”,若响应成功,文件开始断点续传。
断点续传关键部分代码如下:
HANDLE h_file = ::CreateFile(str_path.c_str(), , FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h_file == INVALID_HANDLE_VALUE)
{
return false;
}
int dld_size = ::GetFileSize(h_file, nullptr);
::CloseHandle(h_file);
//
int file_size = GetFileInfo(f).GetSize();
if (file_size == dld_size)
{
cout << "File already downloaded!\n";
return false;
}
//
int read_start = dld_size + ;
file.open(str_path, fstream::out | fstream::app);
//
char buf_num[];
memset(buf_num, , sizeof(buf_num));
_itoa_s(read_start, buf_num, sizeof(buf_num), );
string cmd_dld = "REST ";
cmd_dld += buf_num;
cmd_dld += "\r\n";
//
EnterPasvMode();
//
logger.SendCmd(cmd_dld);
logger.RecvResponse();
if (logger.GetLastLog().substr(, ) == "")
{
cerr << "File name incorrect!\n";
return false;
}
//
cmd_dld = "RETR " + f + "\r\n";
logger.SendCmd(cmd_dld);
logger.RecvResponse();
//
while (::recv(sock_data, dld_file, FILE_SIZE, ) != )
{
cout << strlen(dld_file) << "\n";
file << dld_file;
memset(dld_file, , FILE_SIZE);
}
file.close();
sock_data.Close();
使用c++实现一个FTP客户端(三)的更多相关文章
- 使用c++实现一个FTP客户端(一)
之前使用c++实现了一个FTP客户端,在这里做一些记录. 一.需要注意的几点 ①FTP是一种文件传输协议,基于TCP,所以客户端与服务器建立的连接是可靠.安全的,并且要经过三次握手的过程. ②FTP传 ...
- 使用c++实现一个FTP客户端(二)
接上篇http://www.cnblogs.com/jzincnblogs/p/5213978.html,这篇主要记录编程方面的重点. 客户端使用了Windows Socket提供的API,支持上传. ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
- Socket网络编程--FTP客户端(1)(Windows)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- Socket网络编程--FTP客户端(60篇socket博客,而且都比较简单、深入浅出)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- Python的网络编程[1] -> FTP 协议[2] -> 使用 ftplib 建立 FTP 客户端
使用 ftplib 建立 FTP 客户端 用于建立FTP Client,与 pyftplib 建立的 Server 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 客户端 1. 模块信息 1 ...
- 使用 Socket 通信实现 FTP 客户端程序(来自IBM)
FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层的 Socket 来实现.FTP 客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通 ...
- 【RL-TCPnet网络教程】第37章 RL-TCPnet之FTP客户端
第37章 RL-TCPnet之FTP客户端 本章节为大家讲解RL-TCPnet的FTP客户端应用,学习本章节前,务必要优先学习第35章的FTP基础知识.有了这些基础知识之后,再搞本章节会有事 ...
- 基于线程开发一个FTP服务器
一,项目题目:基于线程开发一个FTP服务器 二,项目要求: 基本要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配 ...
随机推荐
- SWIG和PInvoke学习(1)
1. 简介 SWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具. SWIG能应用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, ...
- python模块之subprocess模块
简述 subprocess意在替代其他几个老的模块或者函数,比如:os.system os.spawn* os.popen* popen2.* commands.*subprocess最简单的用法就是 ...
- POJ1175:Starry Night(bfs)
http://poj.org/problem?id=1175 题目解析: 这个题因为数据的原因可以很水的过,但我因为把1e-8写成了1e-9WA了N遍,一直WA,题目意思很简单就是相似图形(就是求旋转 ...
- file /etc/httpd/conf.d/php.conf from install of php-5.6.37-1.el7.remi.x86_64 conflicts with file from package mod_php71w-7.1.18-1.w7.x86_64
yum remove mod_php71w php71w-cli
- 文本IO 二进制IO
一.文本IO 字符流 使用PrintWriter写入文件后,必须调用close(),否则数据不能正确保存在文件中. Scanner的next()读取一个由分隔符分隔的字符串,nextLine()读取 ...
- 爬取51job职位信息之编码问题
兴趣来潮,爬了下51job,但是遇到编码问题!以下是简单的一段代码 获取整个页面数据 # -*- coding:utf-8 -*- import requests import sysreload(s ...
- 图:无向图(Graph)基本方法及Dijkstra算法的实现 [Python]
一般来讲,实现图的过程中需要有两个自定义的类进行支撑:顶点(Vertex)类,和图(Graph)类.按照这一架构,Vertex类至少需要包含名称(或者某个代号.数据)和邻接顶点两个参数,前者作为顶点的 ...
- Django:学习笔记(9)——视图
Django:学习笔记(9)——视图 基础视图 基于函数的视图,我们需要在使用条件语句来判断请求类型,并分支处理.但是在基于类的视图中,我们可以在类中定义不同请求类型的方法来处理相对应的请求. 基于函 ...
- Java 和 Python 解析动态 key 的 JSON 数据
一.概述 解析JSON过程中,什么情况都可能遇到.遇到特殊的情况,不会怎么办?肯定不是设计的问题,一定是你的姿势不对. 有这样一种JSON需要解析: { "b3444533f6544&quo ...
- 测试人必备:国内外最好用的6款Bug跟踪管理系统
在移动互联网产品中,Bug会导致软件产品在某种程度上不能满足用户的需要.确保一个项目进展顺利,关键在于妥善处理软件中的BUG,那么,如何高效的管理BUG,解决BUG?在这里,我为大家搜集了几款优秀的B ...