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();
}
/**