FTP客户端代码实现demo_v1.0

写的不是特别好,算是初次尝试,还是懂的了不少。

写一个Ftp客户端第一件事情应该是初始化winsock。

//////////////////////////////////////////////////////////////////
//author:YSI
//date:2012-04-21
//version:1.0
#include "main.h"
#include "initsock.h"

using namespace std;

CInitSock initSock;//初始化Winsock库

CInitSock类主要是初始化Winsock类的,完成加载Winsock(WSAStartup),确定使用的sock版本等内容。

//////////////////////////////////////////////////////////
// initsock.h文件

#include <winsock2.h>
#pragma comment(lib, "WS2_32")    // 链接到WS2_32.lib

class CInitSock        
{
public:
    CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
    {
        // 初始化WS2_32.dll
        WSADATA wsaData;  //WSA结构体里有DLL库的详细信息
        WORD sockVersion = MAKEWORD(minorVer, majorVer);//将BYTE型的min和maj合并成一个WORD型
        if(::WSAStartup(sockVersion, &wsaData) != 0)//加载Winsock库
        {
            exit(0);
        }
    }
    ~CInitSock()
    {    
        ::WSACleanup();    
    }
};

Socket套接字就像是一个窗口一样,而输送的信息就好似传信的鸽子一般,只会飞回到他自己的那个窗口中的巢穴里。

窗口(Socket套接字)在刚开始的使用时需要初始化的。

        SOCKET control_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_HOPOPTS); //初始化一个套接字,套接字就好像一个窗口一样
        if (control_sock == INVALID_SOCKET)
        {
            cout << "Failed Socket"<<endl;
            return 0;
        }
        /*
        int socket(int domain, int type, int protocol);
      应用程序调用socket函数来创建一个能够进行网络通信的套接字。
      第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;
      第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW
        (WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部);
      第三个参数指定应用程序所使用的通信协议。这里IPPROTO_HOPOPTS为宏,其实就是0.
        */

在初始化好了套接字之后,就可以开始设置你的鸟儿要飞到什么地方的哪个窗口去了----使用sockaddr_in 结构体来初始化服务器的地址和端口号等。

      sockaddr_in serverAddr; //SOCKADDR_IN结构体来指定IP地址和端口号。 
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(21);//设定要连接的服务器端口号
        serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//指定服务器地址

之后,使用套接字连接,这样,你的鸽子就知道你家在哪里,应该从哪里飞进来,也知道要去哪里,应该从哪里进去。连接成功后会从服务器端发回欢迎信息。

        if (connect(control_sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == -1)//用指定的套接字对指定的地址(服务器)进行连接
        {
            cout << "Failed connect"<<endl;//建立失败就返回
            return 0;
        }

recv接受欢迎信息。

     char buff[256];
        int nRecv = recv(control_sock, buff, 256, 0);//建立好后开始接受数据,接受欢迎数据,等等。nRecv得到的是他发送过来的字节数
        if (nRecv > 0)
        {
            buff[nRecv] = '\0';
            cout << buff << endl;
        }

接受到欢迎信息之后,就可以进行登录,认证后可以进行下载上传。

        char send_buff[256], read_buff[256];

        memset(send_buff, 0, 256);
        memset(read_buff, 0, 256);
        sprintf(send_buff, "USER %s\r\n", "yc");

        send(control_sock, send_buff, strlen(send_buff), 0);
        recv(control_sock, read_buff, 256, 0);
        cout << read_buff << endl;

        memset(send_buff, 0, 256);
        memset(read_buff, 0, 256);
        sprintf(send_buff, "PASS %s\r\n", "123");

这里使用ftp被动模式(passive)。在被动模式中需要注意的是,他发送过来的端口号是<h1,h2,h3,h4,p1,p2>的模式。前四个目前不会用到,而他传数据的端口

p=p1*256+p2;其他都还好。

     sprintf(send_buff,"PASV\r\n");//进入被动模式

        send(control_sock, send_buff, strlen(send_buff), 0);
        recv(control_sock, read_buff, 256, 0); //得到的最终端口号为p = p1×256+p2,这里受到<h1,h2,h3,h4,p1,p2>  

于是,我们可以得到端口号,可以建立一个新的套接字,进行数据的传送了。

        SOCKET data_sock = socket(AF_INET, SOCK_STREAM, 0);
        serverAddr.sin_port = htons(Portnum);//设定端口号p

        if (connect(data_sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == -1)//用指定的套接字对指定的地址(服务器)进行连接
        {
            cout << "Failed data_connect"<<endl;//建立失败就返回
            return 0;
        }

然后经过命令CWD,SIZE,得到了我们所需下载的东西的地址和大小。现在可以开始下载了。下载是RETR命令。

        sprintf(send_buff,"RETR \\boltsdk\\tools\\CurveTool.exe\r\n");
        send(control_sock, send_buff, strlen(send_buff), 0);//准备好收东西啦
        recv(control_sock,read_buff, 256, 0);
        cout << read_buff << endl;

之后就是下载啦。这里用的是FILE类,很久没有用过文件操作了,一开始用还不好使,汗呀。。

        FILE *f1;
        f1 = fopen("H:\\CurveTool.exe","a+b");
        if (f1 == NULL)
        {
            cout << "File ERROR"<<endl;
            return 0;
        }

        while (srcsize > 0)
        {
            memset(read_buff, 0 , 256);
            int revsize = recv(data_sock, read_buff, 256, 0);
            srcsize = srcsize - revsize;
            fwrite(read_buff, sizeof(char), revsize, f1);
        }
        fclose(f1);

完成了操作之后就关闭套接字,就OK了=。=~

        closesocket(control_sock);
        closesocket(data_sock);

很久没有写网络编程了,东西都被我忘记的差不多了,由于之前那个博客因为很多原因被自己删掉了,所以很多做过的东西忘记了也很难在从曾经的项目上找到痕迹,这让我领悟到留下曾经痕迹的重要性。这是我决定重新开一个放代码博客的原因。

TX空间是很好,但是代码这样的东西,还是分享出来的好。

空间就拿来写日记好啦。这里放点自己写的心得体会的好。


原文地址:https://www.cnblogs.com/marylins/p/2461653.html