您的位置:首页 > 理论基础 > 计算机网络

Socket网络编程--FTP客户端(2)(Windows)

2015-05-28 18:55 393 查看
  上一篇FTP客户端讲到如果制作一个简单的FTP客户端,功能实现了,但是后面我们发现了问题,就是FTP是使用明文进行操作的。对于普通情况来说就无所谓了。但有时候要安全的一点的话,就应该使用FTP的安全版本。有SFTP和FTPs,两者都是FTP的安全版本,但是两者的实现原理差别还是很大的,具体自己搜索了解。

0.环境安装

  环境使用我的这一篇文章安装好libssh2库。

  http://www.cnblogs.com/wunaozai/p/4528394.html

  使用一个带有SFTP功能的FTP服务器。注意有些FTP服务器是不带SFTP功能的。这里我使用这个FreeSSHd作为SFTP服务器。

  http://www.freesshd.com/?ctt=download

  关于freesshd配置说两句,Server status标签 点击确定SSH server is running。SSH标签,确定配置完成。Authentication标签下Password authentication为Allowed,Public key authentication为Disabled,这样做的原因是我接下来要做的程序只支持密码登录,减少不必要的干扰,如果有需要,可以自己设定。Tunneling标签,所有选项选中,如果没有选中,本地如果网络复杂的话,可能会有问题。SFTP标签,选择一个作为FTP的根目录。Users标签,增加一个用户。基本设置就这些了。

  

#include "libssh2_config.h"
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <winsock2.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>

#define PORT 22
#define HOST "127.0.0.1"
#define USER "user"
#define PWD  "user"
#define FILENAME "wunaozai.txt"
#define LOCLFILE "wunaozai.txt"

long tvdiff(struct timeval newer, struct timeval older);
int waitsocket(int socket_fd, LIBSSH2_SESSION *session);

int main(int argc, char *argv[])
{
int sock, i;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
struct timeval start;
struct timeval end;
int total = 0;
long time_ms;
int spin = 0;
int ret=0;
int rc=1;
FILE * fp;

WSADATA wsadata;
ret = WSAStartup(MAKEWORD(2,0), &wsadata);
if (ret != 0) {
fprintf(stderr, "WSAStartup failed with error: %d\n", ret);
return 1;
}

ret = libssh2_init (0);
if (ret != 0) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", ret);
return 1;
}

sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //SFTP默认端口为22端口
sin.sin_addr.S_un.S_addr = inet_addr(HOST);
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}

session = libssh2_session_init(); //创建一个session
if (!session) return -1;

libssh2_session_set_blocking(session, 0); //设置为非阻塞方式

while ((ret = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN) //创建一个SSH session
;

if (ret) {
fprintf(stderr, "Failure establishing SSH session: %d\n", ret);
return -1;
}
//到这里我们还没有权限访问,所以接下来要做的是检查hostkey's finger
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
fprintf(stderr, "Fingerprint: ");
for(i = 0; i < 20; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n");

//只是用密码进行验证
while ((ret = libssh2_userauth_password(session, USER, PWD)) == LIBSSH2_ERROR_EAGAIN)
;
if (ret) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown2;
}

fprintf(stderr, "libssh2_sftp_init()!\n");
do {
sftp_session = libssh2_sftp_init(session);
if(!sftp_session) {
if(libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "non-blocking init\n");
waitsocket(sock, session); /* now we wait */
}
else {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown2;
}
}
} while (!sftp_session);

fprintf(stderr, "libssh2_sftp_open()!\n");

//请求一个文件,通过ssh方式
do {
sftp_handle = libssh2_sftp_open(sftp_session, FILENAME, LIBSSH2_FXF_READ, 0);

if (!sftp_handle) {
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown2;
}
else {
fprintf(stderr, "non-blocking open\n");
waitsocket(sock, session); /* now we wait */
}
}
} while (!sftp_handle);

gettimeofday(&start,NULL);
//打开文件进行保存
fp = fopen(LOCLFILE,"wb");
if(fp==NULL)
{
fprintf(stderr,"Can't open local file %s\n",LOCLFILE);
return -1;
}
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
do {
char mem[1024*24];

/* loop until we fail */
while ((ret = libssh2_sftp_read(sftp_handle, mem, sizeof(mem))) == LIBSSH2_ERROR_EAGAIN) {
spin++;
waitsocket(sock, session); /* now we wait */
}
if (ret > 0) {
total += ret;
//write(1, mem, ret);
fwrite(mem,1,ret,fp); //写入到文件中
} else {
break;
}
} while (1);
fclose(fp);
gettimeofday(&end,NULL);
time_ms = tvdiff(end, start);
//打印传输速率
fprintf(stderr, "Got %.4lf Mbytes in %.2lf sec = %.4lf Kbytes/sec spin: %d\n", total/1024.0/1024.0,
time_ms/1000.0, total/((time_ms+1)/1000.0)/1024/1024, spin );

libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session);

rc = 0;//执行到改行代码表示已经正常下载文件

shutdown2:

fprintf(stderr, "libssh2_session_disconnect\n");
while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you") == LIBSSH2_ERROR_EAGAIN)
;
libssh2_session_free(session);
closesocket(sock);
fprintf(stderr, "all done\n");
libssh2_exit();

return rc;
}

long tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*1000+(newer.tv_usec-older.tv_usec)/1000;
}

int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int ret;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
ret = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
return ret;
}


View Code
  至于用到的libssh2_config.h这个文件,没有的话可以在代码中注释掉.

  


  下面这个是freesshd产生的日志中一部分

05-28-2015 14:18:05 HOST localhost SSH connection attempt.
05-28-2015 14:18:05 HOST localhost SSH user successfully logged on using password.
05-28-2015 14:18:06 SFTP service granted to user user.
05-28-2015 14:18:06 HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
05-28-2015 14:18:06 HOST localhost SSH user disconnected.
05-28-2015 14:18:23 HOST localhost SSH connection attempt.
05-28-2015 14:18:23 HOST localhost SSH user successfully logged on using password.
05-28-2015 14:18:23 SFTP service granted to user user.
05-28-2015 14:18:23 HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
05-28-2015 14:18:23 HOST localhost SSH user disconnected.
05-28-2015 14:18:49 HOST localhost SSH connection attempt.
05-28-2015 14:18:49 HOST localhost SSH user successfully logged on using password.
05-28-2015 14:18:49 SFTP service granted to user user.
05-28-2015 14:18:49 HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
05-28-2015 14:18:49 HOST localhost SSH user disconnected.
05-28-2015 14:18:55 HOST localhost SSH connection attempt.
05-28-2015 14:18:56 HOST localhost SSH user successfully logged on using password.
05-28-2015 14:18:56 SFTP service granted to user user.
05-28-2015 14:18:56 HOST localhost user is downloading wunaozai.txt (E:\wunaozai.txt)
05-28-2015 14:18:56 HOST localhost SSH user disconnected.


  有了上面这两个主要的功能,SFTP的客户端就基本功能实现了,至于mkdir和dir功能就参考里面的示例程序,基本都可以看懂。

3.使用putty连接freesshd

  了解过SFTP原理之后,就知道,SFTP其实跟FTP没有多大的关系,其实就是一个使用SSH协议,然后进行会话,会话过程保存为文件,嗯,大概就是这个样子了。所以我们可以使用普通的ssh软件进行登录,拿到该SFTP服务器站点的SHELL。然后可以各种操作,看起来很危险的样子,所以不管用什么SFTP服务器在配置用户的时候要注意的。 putty工具里面还有个PSFTP.exe这个工具可以连接到SFTP服务器,没事的也可以玩玩看。

  


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