使用apache common-net包装实现tftp server

该博客介绍如何使用Apache Commons Net库创建一个TFTP服务器。首先,展示了POM文件中引入该库的依赖。然后,详细讲解了TFTPServer类的实现,包括服务器的启动、停止、模式设置等。TFTPServer类能够处理多个客户端同时连接,并遵循RFC 1350标准。此外,还提供了示例代码展示如何启动和关闭服务器。
摘要由CSDN通过智能技术生成

1、POM文件定义:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>multi-project-parent</artifactId>
        <groupId>multi-project-parent</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tftp</artifactId>

    <dependencies>
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
    </dependencies>
</project>

==========================================================================

2、Server实现:

package com.wolf.tftp.server;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.HashSet;
import java.util.Iterator;

import com.wolf.tftp.common.Constants;
import com.wolf.tftp.common.Constants;
import org.apache.commons.net.io.FromNetASCIIOutputStream;
import org.apache.commons.net.io.ToNetASCIIInputStream;
import org.apache.commons.net.tftp.*;

/**
 * A fully multi-threaded tftp server. Can handle multiple clients at the same time. Implements RFC
 * 1350 and wrapping block numbers for large file support.
 * <p/>
 * To launch, just create an instance of the class. An IOException will be thrown if the server
 * fails to start for reasons such as port in use, port denied, etc.
 * <p/>
 * To stop, use the shutdown method.
 * <p/>
 * To check to see if the server is still running (or if it stopped because of an error), call the
 * isRunning() method.
 * <p/>
 * By default, events are not logged to stdout/stderr. This can be changed with the
 * setLog and setLogError methods.
 * <p/>
 * <p/>
 * Example usage is below:
 * <p/>
 * <code>
 * public static void main(String[] args) throws Exception
 * {
 * if (args.length != 1)
 * {
 * System.out
 * .println("You must provide 1 argument - the base path for the server to serve from.");
 * System.exit(1);
 * }
 * <p/>
 * TFTPServer ts = new TFTPServer(new File(args[0]), new File(args[0]), GET_AND_PUT);
 * ts.setSocketTimeout(2000);
 * <p/>
 * System.out.println("TFTP Server running.  Press enter to stop.");
 * new InputStreamReader(System.in).read();
 * <p/>
 * ts.shutdown();
 * System.out.println("Server shut down.");
 * System.exit(0);
 * }
 * <p/>
 * </code>
 *
 * @author <A HREF="mailto:daniel.armbrust.list@gmail.com">Dan Armbrust</A>
 * @since 2.0
 */
public class TFTPServer implements Runnable {


    public static enum ServerMode {GET_ONLY, PUT_ONLY, GET_AND_PUT;}

    private HashSet<TFTPTransfer> transfers_ = new HashSet<TFTPTransfer>();
    private volatile boolean shutdownServer = true;
    private volatile boolean runningServer = false;
    private TFTP serverTftp_;
    private File serverReadDirectory_;
    private File serverWriteDirectory_;
    private int port_;
    private Exception serverException = null;
    private ServerMode mode_;

    /* /dev/null output stream (default) */
    private static final PrintStream nullStream = new PrintStream(
            new OutputStream() {
                @Override
                public void write(int b) {
                }

                @Override
                public void write(byte[] b) throws IOException {
                }
            }
    );

    // don't have access to a logger api, so we will log to these streams, which
    // by default are set to a no-op logger
    private PrintStream log_;
    private PrintStream logError_;

    private int maxTimeoutRetries_ = 3;
    private int socketTimeout_;
    private Thread serverThread;


    public TFTPServer(File serverReadDirectory, File serverWriteDirectory, ServerMode mode, PrintStream log, PrintStream error)
            throws IOException {
        this(serverReadDirectory, serverWriteDirectory, Constants.DEFAULT_TFTP_PORT, mode, log, error);
    }

    /**
     * Start a TFTP Server on the default port (69). Gets and Puts occur in the specified
     * directories.
     * <p/>
     * The server will start in another thread, allowing this constructor to return immediately.
     * <p/>
     * If a get or a put comes in with a relative path that tries to get outside of the
     * serverDirectory, then the get or put will be denied.
     * <p/>
     * GET_ONLY mode only allows gets, PUT_ONLY mode only allows puts, and GET_AND_PUT allows both.
     * Modes are defined as int constants in this class.
     *
     * @param serverReadDirectory  directory for GET requests
     * @param serverWriteDirectory directory for PUT requests
     * @param mode                 A value as specified above.
     * @throws IOException if the server directory is invalid or does not exist.
     */
    public TFTPServer(File serverReadDirectory, File serverWriteDirectory, ServerMode mode)
            throws IOException {
        this(serverReadDirectory, serverWriteDirectory, Constants.DEFAULT_TFTP_PORT, mode, null, null);
    }

    /**
     * Start a TFTP Server on the specified port. Gets and Puts occur in the specified directory.
     * <p/>
     * The server will start in another thread, allowing this constructor to return immediately.
     * <p/>
     * If a get or a put comes in with a relative path that tries to get outside of the
     * serverDirectory, then the get or put will be denied.
     * <p/>
     * GET_ONLY mode only allows gets, PUT_ONLY mode only allows puts, and GET_AND_PUT allows both.
     * Modes are defined as int constants in this class.
     *
     * @param serverReadDirectory  directory for GET requests
     * @param serverWriteDirectory directory for PUT requests
     * @param mode                 A value as specified above.
     * @param log                  Stream to write log message to. If not provided, uses System.out
     * @param errorLog             Stream to write error messages to. If not provided, uses System.err.
     * @throws IOException if the server directory is invalid or does not exist.
     */
    public TFTPServer(File serverReadDirectory, File serverWriteDirectory, int port, ServerMode mode,
                      PrintStream log, PrintStream errorLog) throws IOException {
        port_ = port;
        mode_ = mode;
        log_ = (log == null ? nullStream : log);
        logError_ = (errorLog == null ? nullStream : errorLog);

        log_.println("Starting TFTP Server on port " + port_ + ".  Read directory: "
                + serverReadDirectory + " Write directory: " + serverWriteDirectory
                + " Server Mode is " + mode_);

        serverReadDirectory_ = serverReadDirectory.getCanonicalFile();
        if (!serverReadDirectory_.exists() || !serverReadDirectory.isDirectory()) {
            throw new IOException("The server read directory " + serverReadDirectory_
                    + " does not exist");
        }

        serverWriteDirectory_ = serverWriteDirectory.getCanonicalFile();
        if (!serverWriteDirectory_.exists() || !serverWriteDirectory.isDirectory()) {
            throw new IOException("The server write directory " + serverWriteDirectory_
                    + " does not exist");
        }
        //launch(serverReadDirectory, serverWriteDirectory);
    }

    /**
     * Set the max number of retries in response to a timeout. Default 3. Min 0.
     *
     * @param retries
     */
    public void setMaxTimeoutRetries(int retries) {
        if (retries < 0) {
            throw new RuntimeException("Invalid Value");
        }
        maxTimeoutRetries_ = retries;
    }

    /**
     * Get the current value for maxTimeoutRetries
     */
    public int getMaxTimeoutRetries() {
        return maxTimeoutRetries_;
    }

    /**
     * Set the socket timeout in milliseconds used in transfers. Defaults to the value here:
     * http://commons.apache.org/net/apidocs/org/apache/commons/net/tftp/TFTP.html#DEFAULT_TIMEOUT
     * (5000 at the time I write this) Min value of 10.
     */
    public void setSocketTimeout(int timeout) {
        if (timeout < 10) {
            throw new RuntimeException("Invalid Value");
        }
        socketTimeout_ = timeout;
    }

    /**
     * The current socket timeout used during transfers in milliseconds.
     */
    public int getSocketTimeout() {
        return socketTimeout_;
    }

    /*
     * start the server, throw an error if it can't start.
     */
    public void launch() {
        shutdownServer = false;
        runningServer = true;

        serverTftp_ = new TFTP();
        // This is the value used in response to each client.
        socketTimeout_ = serverTftp_.getDefaultTimeout();

        // we want the server thread to listen forever.
        serverTftp_.setDefaultTimeout(0);

        try {
            serverTftp_.open(port_);
            System.out.println("TFTP Server is listen on "+port_);
        } catch (SocketException e) {
            shutdownServer = true;
            runningServer = false;
            e.printStackTrace();
        }

        serverThread = new Thread(this);
        serverThread.setDaemon(true);
        serverThread.start();
    }

    @Override
    protected void finalize() throws Throwable {
        shutdown();
    }

    /**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值