亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? sever-3.txt

?? 實現ftp代理服務器的基本功能
?? TXT
字號:
下面我們要處理用戶連接,也就是FtpConnection類。Ftp連接本質上是一個狀態機,當FtpConnection接收到用戶命令后,根據當前狀態決定響應及下一個狀態。不過我們不需要考慮實現一個復雜的狀態機,只須監聽/接收/處理/響應即可:

package jftp;

import java.net.*;
import java.io.*;
import java.util.*;
import java.text.*;

public class FtpConnection extends Thread {
    /** 主目錄 */
    static public String root = null;
    private String currentDir = "/"; // 當前目錄
    private Socket socket;
    private BufferedReader reader = null;
    private BufferedWriter writer = null;
    private String clientIP = null;
    private Socket tempSocket = null; // tempSocket用于傳送文件
    private ServerSocket pasvSocket = null; // 用于被動模式
    private String host = null;
    private int port = (-1);

    public FtpConnection(Socket socket) {
        this.socket = socket;
        this.clientIP = socket.getInetAddress().getHostAddress();
    }

    public void run() {
        String command;
        try {
            System.out.println(clientIP + " connected.");
            socket.setSoTimeout(60000); // ftp超時設定
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            response("220-歡迎消息......");
            response("220-歡迎消息......");
            response("220 注意最后一行歡迎消息沒有“-”");
            for(;;) {
                command = reader.readLine();
                if(command == null)
                    break;
                System.out.println("command from " + clientIP + " : " + command);
                parseCommand(command);
                if(command.equals("QUIT")) // 收到QUIT命令
                    break;
            }
        }
        catch(Exception e) { e.printStackTrace(); }
        finally {
            try {
                if(reader!=null) reader.close();
            }catch(Exception e) {}
            try {
                if(writer!=null) writer.close();
            }catch(Exception e) {}
            try {
                if(this.pasvSocket!=null) pasvSocket.close();
            }catch(Exception e) {}
            try {
                if(this.tempSocket!=null) tempSocket.close();
            }catch(Exception e) {}
            try {
                if(this.socket!=null) socket.close();
            }catch(Exception e) {}
        }
        System.out.println(clientIP + " disconnected.");
    }
}

FtpConnection在run()方法中僅僅是獲得用戶命令/處理命令,當收到QUIT時,關閉連接,結束Ftp會話。

先準備幾個輔助方法:

private void response(String s) throws Exception {
    // System.out.println("  [RESPONSE] "+s);
    writer.write(s);
    writer.newLine();
    writer.flush(); // 注意要flush否則響應仍在緩沖區
}

// 生成一個字符串
private static String pad(int length) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < length; i++)
        buf.append((char)' ');
    return buf.toString();
}

// 獲取參數
private String getParam(String cmd, String start) {
    String s = cmd.substring(start.length(), cmd.length());
    return s.trim();
}

// 獲取路徑
private String translatePath(String path) {
    if(path==null) return root;
    if(path.equals("")) return root;
    path = path.replace('/', '\\');
    return root + path;
}

// 獲取文件長度,注意是一個字符串
private String getFileLength(long length) {
    String s = Long.toString(length);
    int spaces = 12 - s.length();
    for(int i=0; i<spaces; i++)
        s = " " + s;
    return s;
}

接下來便是處理用戶命令,這個方法有點長,需要重構一下,我只是把LIST命令單獨挪了出來:

private void parseCommand(String s) throws Exception {
    if(s==null || s.equals(""))
        return;
    if(s.startsWith("USER ")) {
        response("331 need password");
    }
    else if(s.startsWith("PASS ")) {
        response("230 welcome to my ftp!");
    }
    else if(s.equals("QUIT")) {
        response("221 歡迎再來!");
    }
    else if(s.equals("TYPE A")) {
        response("200 TYPE set to A.");
    }
    else if(s.equals("TYPE I")) {
        response("200 TYPE set to I.");
    }
    else if(s.equals("NOOP")) {
        response("200 NOOP OK.");
    }
    else if(s.startsWith("CWD")) { // 設置當前目錄,注意沒有檢查目錄是否有效
        this.currentDir = getParam(s, "CWD ");
        response("250 CWD command successful.");
    }
    else if(s.equals("PWD")) { // 打印當前目錄
        response("257 \"" + this.currentDir + "\" is current directory.");
    }
    else if(s.startsWith("PORT ")) {
        // 記錄端口
        String[] params = getParam(s, "PORT ").split(",");
        if(params.length<=4 || params.length>=7)
            response("500 command param error.");
        else {
            this.host = params[0] + "." + params[1] + "." + params[2] + "." + params[3];
            String port1 = null;
            String port2 = null;
            if(params.length == 6) {
                port1 = params[4];
                port2 = params[5];
            }
            else {
                port1 = "0";
                port2 = params[4];
            }
            this.port = Integer.parseInt(port1) * 256 + Integer.parseInt(port2);
            response("200 command successful.");
        }
    }
    else if(s.equals("PASV")) { // 進入被動模式
        if(pasvSocket!=null)
            pasvSocket.close();
        try {
            pasvSocket = new ServerSocket(0);
            int pPort = pasvSocket.getLocalPort();
            String s_port;
            if(pPort<=255)
                s_port = "255";
            else {
                int p1 = pPort / 256;
                int p2 = pPort - p1*256;
                s_port = p1 + "," + p2;
            }
            pasvSocket.setSoTimeout(60000);
            response("227 Entering Passive Mode ("
                + InetAddress.getLocalHost().getHostAddress().replace('.', ',')
                + "," + s_port + ")");
        }
        catch(Exception e) {
            if(pasvSocket!=null) {
                pasvSocket.close();
                pasvSocket = null;
            }
        }
    }
    else if(s.startsWith("RETR")) { // 傳文件
        String file = currentDir + (currentDir.endsWith("/") ? "" : "/") + getParam(s, "RETR");
        System.out.println("download file: " + file);
        Socket dataSocket;
        // 根據上一次的PASV或PORT命令決定使用哪個socket
        if(pasvSocket!=null)
            dataSocket = pasvSocket.accept();
        else
            dataSocket = new Socket(this.host, this.port);
        OutputStream dos = null;
        InputStream fis = null;
        response("150 Opening ASCII mode data connection.");
        try {
            fis = new BufferedInputStream(new FileInputStream(translatePath(file)));
            dos = new DataOutputStream(new BufferedOutputStream(dataSocket.getOutputStream()));
            // 開始正式發送數據:
            byte[] buffer = new byte[20480]; // 發送緩沖 20k
            int num = 0; // 發送一次讀取的字節數
            do {
                num = fis.read(buffer);
                if(num!=(-1)) {
                    // 發送:
                    dos.write(buffer, 0, num);
                    dos.flush();
                }
            } while(num!=(-1));
            fis.close();
            fis = null;
            dos.close();
            dos = null;
            dataSocket.close();
            dataSocket = null;
            response("226 transfer complete."); // 響應一個成功標志
        }
        catch(Exception e) {
            response("550 ERROR: File not found or access denied.");
        }
        finally {
            try {
                if(fis!=null) fis.close();
                if(dos!=null) dos.close();
                if(dataSocket!=null) dataSocket.close();
            }
            catch(Exception e) {}
        }
    }
    else if(s.equals("LIST")) { // 列當前目錄文件
        Socket dataSocket;
        // 根據上一次的PASV或PORT命令決定使用哪個socket
        if(pasvSocket!=null)
            dataSocket = pasvSocket.accept();
        else
            dataSocket = new Socket(this.host, this.port);
        PrintWriter writer = new PrintWriter(new BufferedOutputStream(dataSocket.getOutputStream()));
        response("150 Opening ASCII mode data connection.");
        try {
            responseList(writer, this.currentDir);
            writer.close();
            dataSocket.close();
            response("226 transfer complete.");
        }
        catch(IOException e) {
            writer.close();
            dataSocket.close();
            response(e.getMessage());
        }
        dataSocket = null;
    }
    else {
        response("500 invalid command"); // 沒有匹配的命令,輸出錯誤信息
    }
}

// 響應LIST命令
private void responseList(PrintWriter writer, String path) throws IOException {
    File dir = new File(translatePath(path));
    if(!dir.isDirectory())
        throw new IOException("550 No such file or directory");
    File[] files = dir.listFiles();
    String dateStr;
    for(int i=0; i<files.length; i++) {
        dateStr = new SimpleDateFormat("MMM dd hh:mm").format(new Date(files[i].lastModified()));
        if(files[i].isDirectory()) {
            writer.println("drwxrwxrwx  1 ftp      System            0 "
            + dateStr + " " + files[i].getName());
        }
        else {
            writer.println("-rwxrwxrwx  1 ftp      System "
            + getFileLength(files[i].length()) + " " + dateStr + " " + files[i].getName());
        }
    }

    String file_header = "-rwxrwxrwx  1 ftp      System            0 Aug  5 19:59 ";
    String dir_header =  "drwxrwxrwx  1 ftp      System            0 Aug 15 19:59 ";
    writer.println("total " + files.length);
    writer.flush();
}

(待續)

基本上我們的Ftp已經可以運行了,注意到我們在FtpConnection中處理USER和PASS命令,直接返回200 OK,如果需要驗證用戶名和口令,還需要添加相應的代碼。

如何調試Ftp服務器?

有個最簡單的方法,便是使用現成的Ftp客戶端,推薦CuteFtp,因為它總是把客戶端發送的命令和服務器響應打印出來,我們可以非常方便的看到服務器的輸出結果。

另外一個小Bug,文件列表在CuteFtp中可以正常顯示,在其他Ftp客戶端不一定能正常顯示,這說明輸出響應的“兼容性”還不夠好,有空了看看Ftp的RFC再改進!:)

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美综合一区二区| 黄色日韩三级电影| 自拍偷自拍亚洲精品播放| 久久久五月婷婷| 久久免费美女视频| 国产亚洲福利社区一区| 国产午夜精品一区二区三区四区| 欧美videos大乳护士334| 欧美大黄免费观看| 久久久精品黄色| 欧美国产激情一区二区三区蜜月| 久久精品一区二区三区av| 久久久久久久国产精品影院| 欧美激情综合五月色丁香| 国产精品久久久久久久久快鸭 | 亚洲成年人网站在线观看| 亚洲欧洲国产专区| 一区二区三区 在线观看视频| 亚洲国产精品人人做人人爽| 免费成人在线网站| 国产精品66部| 欧洲视频一区二区| 日韩一区二区免费在线电影| 欧美精品一区二区蜜臀亚洲| 国产精品久久二区二区| 亚洲欧美日韩久久| 美女脱光内衣内裤视频久久网站 | 国产精品萝li| 一区二区三区日韩欧美| 日本强好片久久久久久aaa| 久久99久久久欧美国产| 成人国产精品免费网站| 欧美吞精做爰啪啪高潮| 国产亚洲1区2区3区| 亚洲va欧美va国产va天堂影院| 蜜臀精品一区二区三区在线观看| 成人美女视频在线观看| 在线不卡一区二区| 中文欧美字幕免费| 爽好多水快深点欧美视频| 国产一区二区三区不卡在线观看| 色成年激情久久综合| 久久欧美中文字幕| 亚洲午夜免费电影| 波多野结衣在线aⅴ中文字幕不卡| 欧美日本乱大交xxxxx| 国产精品国产三级国产三级人妇 | 欧美激情在线观看视频免费| 亚洲一区二区av电影| 国产成人精品网址| 欧美精选一区二区| 国产精品久久久久aaaa樱花 | 92精品国产成人观看免费| 日韩视频一区在线观看| 亚洲综合激情另类小说区| 成人三级伦理片| 日韩欧美国产午夜精品| 亚洲成在线观看| 色综合久久中文综合久久牛| 国产调教视频一区| 国内不卡的二区三区中文字幕| 在线播放国产精品二区一二区四区| 国产精品免费av| 国产a精品视频| 精品国产一区二区三区av性色| 亚洲成人av一区二区三区| 色婷婷精品久久二区二区蜜臀av | 国产一区二区精品久久91| 91精品国产色综合久久不卡电影| 亚洲男人的天堂在线aⅴ视频| 国产精品小仙女| 国产亚洲午夜高清国产拍精品| 麻豆极品一区二区三区| 欧美肥妇free| 亚洲第一福利视频在线| 欧美日韩国产a| 久久国产福利国产秒拍| 911精品国产一区二区在线| 一区二区三区精密机械公司| 91美女片黄在线观看91美女| 亚洲免费毛片网站| 91久久线看在观草草青青| 一区二区三区在线视频免费观看| 91啦中文在线观看| 一区二区三区中文字幕| 欧美成人官网二区| 麻豆久久久久久久| 国产三级久久久| 国产91露脸合集magnet| 国产精品国产三级国产专播品爱网| 高清国产一区二区| 中文字幕一区二| 在线免费观看日本欧美| 免费在线观看精品| 久久精品视频一区二区三区| 成人免费毛片aaaaa**| 亚洲日本一区二区三区| 51久久夜色精品国产麻豆| 国产一区二区三区在线观看免费视频 | 五月天亚洲婷婷| 欧美精品一区二区三区久久久| 不卡视频在线看| 婷婷中文字幕一区三区| 精品国产露脸精彩对白 | 色综合久久久网| 亚洲成人www| 精品国产凹凸成av人网站| 成人精品一区二区三区四区| 亚洲女人的天堂| 制服丝袜成人动漫| 国产成人福利片| 亚洲.国产.中文慕字在线| 精品久久久久久亚洲综合网| 99热精品一区二区| 日韩精品高清不卡| 欧美午夜电影一区| 国产一区不卡精品| 亚洲成a人v欧美综合天堂| 国产欧美一区二区精品性色| 欧美日韩视频在线一区二区| 国产精品123区| 日韩不卡手机在线v区| 中文字幕一区二区在线播放| 欧美一二三区在线观看| 99久精品国产| 国产高清不卡二三区| 日韩不卡一区二区三区| 亚洲国产视频网站| 中文字幕在线一区| 久久奇米777| 日韩欧美一二三| 欧美日韩亚洲国产综合| 91亚洲国产成人精品一区二区三| 久久精品国产第一区二区三区| 亚洲激情图片小说视频| 久久先锋影音av| 日韩一级片在线播放| 在线看国产一区二区| 91色porny| 成人av免费在线| 国产成人亚洲综合色影视| 久久国产精品无码网站| 日本伊人午夜精品| 日韩成人av影视| 日本sm残虐另类| 日本中文字幕一区二区视频 | 日韩国产高清在线| 亚洲国产成人va在线观看天堂| 亚洲欧美国产毛片在线| 国产精品久久毛片av大全日韩| 久久先锋影音av鲁色资源网| 精品成人一区二区| 欧美电视剧免费全集观看 | 国产真实乱偷精品视频免| 日本中文字幕一区二区视频| 日韩电影一二三区| 日本 国产 欧美色综合| 青青草成人在线观看| 免费一级片91| 久久99精品国产.久久久久久| 蜜臀91精品一区二区三区| 免费精品视频在线| 极品瑜伽女神91| 国产精品主播直播| 粉嫩一区二区三区在线看| 国产91丝袜在线观看| 色综合久久久久久久久| 欧美影院精品一区| 宅男噜噜噜66一区二区66| 欧洲国产伦久久久久久久| 久久久久国产精品厨房| 久久久国产一区二区三区四区小说 | 一区二区三区四区不卡视频| 一区二区成人在线| 日韩成人一区二区三区在线观看| 日本午夜精品视频在线观看| 九色综合狠狠综合久久| 国产福利91精品| 91麻豆产精品久久久久久| 欧美性视频一区二区三区| 67194成人在线观看| 久久午夜国产精品| 亚洲欧美福利一区二区| 日本亚洲三级在线| 不卡一区中文字幕| 在线电影国产精品| 国产婷婷色一区二区三区| 亚洲制服丝袜av| 国产一区二区美女| 欧美视频三区在线播放| 久久在线免费观看| 亚洲激情综合网| 国产东北露脸精品视频| 欧美日韩成人综合| 欧美国产日韩a欧美在线观看| 亚洲午夜日本在线观看| 粉嫩av亚洲一区二区图片| 欧美日韩国产精品自在自线| 国产精品国产三级国产普通话三级| 亚洲成年人网站在线观看|