前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java代码实现FTP协议

java代码实现FTP协议

作者头像
望月从良
发布2020-03-17 17:35:40
1.1K0
发布2020-03-17 17:35:40
举报
文章被收录于专栏:Coding迪斯尼Coding迪斯尼

前几节我们完成了ftp协议的主要讲解,同时使用wireshark抓包了解ftp数据协议包的特征,本节我们使用代码完成ftp协议,代码将模仿ftp客户端,它与服务器建立连接后,使用用户名和密码登陆服务器,然后获得服务器的当前目录内容,继而通过数据连接获取服务器推送目录具体信息,最后客户端关闭,下面我们看看具体的代码实现,首先在工程目录下新建名为FTPClient的类,相关实现如下:

代码语言:javascript
复制
package Application;

import java.net.InetAddress;

import utils.IFTPDataReceiver;
import utils.ITCPHandler;

public class FTPClient implements ITCPHandler, IFTPDataReceiver{
    private  TCPThreeHandShakes  tcp_socket = null;
    private  int data_port = 0;
    private FTPDataReceiver data_receiver = null;
    private String server_ip;
    @Override
    public void connect_notify(boolean connect_res) {
         if (connect_res == true) {
             System.out.println("connect ftp server ok!");
         }
    }

    @Override
    public void send_notify(boolean send_res, byte[] packet_send) {
        // TODO Auto-generated method stub

    }

    @Override
    public void recv_notify(byte[] packet_recv) {
        try {
            String server_return = new String(packet_recv, "ASCII");
            System.out.println("receive info from ftp server: " +  server_return);
            String return_code = server_return.substring(0, 3);
            String return_str = server_return.substring(3);
            if (return_code.equals("220")) {
                System.out.println("receive code 220: " + return_str);
                send_command("USER chenyi\r\n");
            }
            if (return_code.equals("331")) {
                System.out.println("receive code 331: " + return_str);
                //服务器请求用户名密码
                send_command("PASS 1111\r\n");
            }
            if (return_code.equals("230")) {
                System.out.println("receive code 230: " + return_str);
                //用户登录成功
                send_command("PWD\r\n"); //获取服务器文件目录
            }
            if (return_code.equals("257")) {
                System.out.println("receive code 257: " + return_str);
                send_command("PASV\r\n");
            }
            if (return_code.equals("227")) {
                System.out.println("receive code 227: " + return_str);
                int ip_port_index = return_str.indexOf("(");
                String port_str = return_str.substring(ip_port_index);
                int ip_count = 4; //经过4个逗号就能找到端口
                while (ip_count > 0) {
                    int idx = port_str.indexOf(',');
                    ip_count--;
                    port_str = port_str.substring(idx + 1);
                }
                int idx = port_str.indexOf(',');
                String p1 = port_str.substring(0, idx);
                port_str = port_str.substring(idx + 1);
                idx = port_str.indexOf(')');
                String p2 = port_str.substring(0, idx);
                int port = Integer.parseInt(p1) * 256 + Integer.parseInt(p2);
                System.out.println("get data port : " + port);
                data_port = port;
                send_command("TYPE A\r\n"); //通知服务器以ASCII的方式传输数据
            }
            if  (return_code.equals("200")) { //服务器同意使用ASCII方式传递数据
                System.out.println("receive code 200: " + return_str);
                send_command("LIST\r\n");//要求服务器传输当前目录下的文件信息
                data_receiver = new FTPDataReceiver(server_ip, data_port, this);
                data_receiver.get_data();
            }
            if (return_code.equals("150")) { //服务器通知数据发送完毕
                System.out.println("receive code 150: " + return_str);
                tcp_socket.tcp_close();
            }
            //tcp_socket.tcp_close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private void send_command(String command) {
        try {
            tcp_socket.tcp_send(command.getBytes());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void connect_close_notify(boolean close_res) {
        // TODO Auto-generated method stub

    }

    public void run() {
         try {
            InetAddress ip = InetAddress.getByName("192.168.2.127"); //连接ftp服务器
            server_ip = "192.168.2.127";
            short port = 20000;
            tcp_socket = new TCPThreeHandShakes(ip.getAddress(), port, this);
            tcp_socket.tcp_connect();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void receive_ftp_data(byte[] data) {
        System.out.println("Successfuly get ftp data");
        String ftp_data = new String(data);
        System.out.println("content of ftp_data: " + ftp_data);
    }

}

代码实现中recv_notify用来解读服务器返回的信息,前三个字符是服务器的返回码,后面字符串是对返回码的解释。这里值得关注的是当客户端向服务器发送PSAV命令后,服务器返回码为227,其中的字符串包含了用于数据传输的端口,代码需要解读返回字符串,然后计算出端口,并像服务器发送TYPE A命令告诉服务器通过ASCII模式传输数据。最后启动新的tcp连接去接收数据。一旦在数据端口与服务器实现三次握手后,服务器会主动给我们推送数据。在完成PSAV命令后,代码向服务器发送LIST命令,要求服务器给出当前目录下的所有文件信息,然后代码创建FTPDataReceiver实例,该对象负责通过数据端口与服务器连接,同时等待服务器推送数据,接收完数据后他把接收到的内容推送给FTPClient对象,我们看FTPDataReceiver的实现:

代码语言:javascript
复制
package Application;

import java.net.InetAddress;
import java.nio.ByteBuffer;

import utils.IFTPDataReceiver;
import utils.ITCPHandler;

public class FTPDataReceiver implements ITCPHandler{
    private int data_port = 0;
    private IFTPDataReceiver data_receiver = null;
    private  TCPThreeHandShakes  tcp_socket = null;
    private String server_ip = "";
    private byte[] data_buffer = new byte[4096];
    private ByteBuffer byteBuffer = null;
    public FTPDataReceiver(String ip, int port, IFTPDataReceiver receiver) {
        this.data_port = port;
        this.data_receiver = receiver;
        this.server_ip = ip;
        byteBuffer = ByteBuffer.wrap(data_buffer);
    }


    public void get_data() {
         try {
             InetAddress ip = InetAddress.getByName(server_ip); //连接ftp服务器
             tcp_socket = new TCPThreeHandShakes(ip.getAddress(), (short)data_port, this);
             tcp_socket.tcp_connect();
         } catch (Exception e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
    }

    @Override
    public void connect_notify(boolean connect_res) {
        if (connect_res) {
            System.out.println("ftp data connection ok");
        } else {
            System.out.println("ftp data connection fail");
        }

    }

    @Override
    public void send_notify(boolean send_res, byte[] packet_send) {
        // TODO Auto-generated method stub

    }

    @Override
    public void recv_notify(byte[] packet_recv) {
        System.out.println("ftp receiving data");
        byteBuffer.put(packet_recv);
    }

    @Override
    public void connect_close_notify(boolean close_res) {
        try {
            tcp_socket.tcp_close();
            data_receiver.receive_ftp_data(byteBuffer.array());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

完成上面代码后运行,我们可以得到如下结果:

从图中可以看到,我们代码成功接收了ftp服务器推送的目录信息。更多详细讲解和代码调试演示请点击’阅读原文‘。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coding迪斯尼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档