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();
}
/**
* check if the server thread is still running.
*
* @return true if running, false if stopped.
* @throws Exception throws the exception that stopped the server if the server is stopped from
* an exception.
*/
public boolean isRunning() throws Exception {
if (serverException != null) {
throw serverException;
}
return runningServer;
}
public void run() {
try {
while (!shutdownServer) {
TFTPPacket tftpPacket;
tftpPacket = serverTftp_.receive();
TFTPTransfer tt = new TFTPTransfer(tftpPacket);
synchronized (transfers_) {
transfers_.add(tt);
}
Thread thread = new Thread(tt);
thread.setDaemon(true);
thread.start();
}
} catch (Exception e) {
if (!shutdownServer) {
serverException = e;
logError_.println("Unexpected Error in TFTP Server - Server shut down! + " + e);
}
} finally {
shutdownServer = true; // set this to true, so the launching thread can check to see if it started.
runningServer = false;
if (serverTftp_ != null && serverTftp_.isOpen()) {
serverTftp_.close();
}
}
}
/**
* Stop the tftp server (and any currently running transfers) and release all opened network
* resources.
*/
public void shutdown() {
shutdownServer = true;
runningServer = false;
synchronized (transfers_) {
Iterator<TFTPTransfer> it = transfers_.iterator();
while (it.hasNext()) {
it.next().shutdown();
}
}
try {
serverTftp_.close();
} catch (RuntimeException e) {
// noop
}
try {
serverThread.join();
} catch (InterruptedException e) {
// we've done the best we could, return
}
log_.flush();
logError_.flush();
log_.close();
logError_.close();
}
/*
* An instance of an ongoing transfer.
*/
private class TFTPTransfer implements Runnable {
private TFTPPacket tftpPacket_;
private boolean shutdownTransfer = false;
TFTP transferTftp_ = null;
public TFTPTransfer(TFTPPacket tftpPacket) {
tftpPacket_ = tftpPacket;
}
public void shutdown() {
shutdownTransfer = true;
try {
transferTftp_.close();
} catch (RuntimeException e) {
// noop
}
}
public void run() {
try {
transferTftp_ = new TFTP();
transferTftp_.beginBufferedOps();
transferTftp_.setDefaultTimeout(socketTimeout_);
transferTftp_.open();
if (tftpPacket_ instanceof TFTPReadRequestPacket) {
handleRead(((TFTPReadRequestPacket) tftpPacket_));
} else if (tftpPacket_ instanceof TFTPWriteRequestPacket) {
handleWrite((TFTPWriteRequestPacket) tftpPacket_);
} else {
log_.println("Unsupported TFTP request (" + tftpPacket_ + ") - ignored.");
}
} catch (Exception e) {
e.printStackTrace();
if (!shutdownTransfer) {
logError_
.println("Unexpected Error in during TFTP file transfer. Transfer aborted. "
+ e);
}
} finally {
try {
if (transferTftp_ != null && transferTftp_.isOpen()) {
transferTftp_.endBufferedOps();
transferTftp_.close();
}
} catch (Exception e) {
// noop
}
synchronized (transfers_) {
transfers_.remove(this);
}
}
}
/*
* Handle a tftp read request.
*/
private void handleRead(TFTPReadRequestPacket trrp) throws IOException, TFTPPacketException {
InputStream is = null;
try {
if (mode_ == ServerMode.PUT_ONLY) {
transferTftp_.bufferedSend(new TFTPErrorPacket(trrp.getAddress(), trrp
.getPort(), TFTPErrorPacket.ILLEGAL_OPERATION,
"Read not allowed by server."));
return;
}
try {
is = new BufferedInputStream(new FileInputStream(buildSafeFile(
serverReadDirectory_, trrp.getFilename(), false)));
} catch (FileNotFoundException e) {
transferTftp_.bufferedSend(new TFTPErrorPacket(trrp.getAddress(), trrp
.getPort(), TFTPErrorPacket.FILE_NOT_FOUND, e.getMessage()));
return;
} catch (Exception e) {
transferTftp_.bufferedSend(new TFTPErrorPacket(trrp.getAddress(), trrp
.getPort(), TFTPErrorPacket.UNDEFINED, e.getMessage()));
return;
}
if (trrp.getMode() == TFTP.NETASCII_MODE) {
is = new ToNetASCIIInputStream(is);
}
byte[] temp = new byte[TFTPDataPacket.MAX_DATA_LENGTH];
TFTPPacket answer;
int block = 1;
boolean sendNext = true;
int readLength = TFTPDataPacket.MAX_DATA_LENGTH;
TFTPDataPacket lastSentData = null;
// We are reading a file, so when we read less than the
// requested bytes, we know that we are at the end of the file.
while (readLength == TFTPDataPacket.MAX_DATA_LENGTH && !shutdownTransfer) {
if (sendNext) {
readLength = is.read(temp);
if (readLength == -1) {
readLength = 0;
}
lastSentData = new TFTPDataPacket(trrp.getAddress(), trrp.getPort(), block,
temp, 0, readLength);
transferTftp_.bufferedSend(lastSentData);
}
answer = null;
int timeoutCount = 0;
while (!shutdownTransfer
&& (answer == null || !answer.getAddress().equals(trrp.getAddress()) || answer
.getPort() != trrp.getPort())) {
// listen for an answer.
if (answer != null) {
// The answer that we got didn't come from the
// expected source, fire back an error, and continue
// listening.
log_.println("TFTP Server ignoring message from unexpected source.");
transferTftp_.bufferedSend(new TFTPErrorPacket(answer.getAddress(),
answer.getPort(), TFTPErrorPacket.UNKNOWN_TID,
"Unexpected Host or Port"));
}
try {
answer = transferTftp_.bufferedReceive();
} catch (SocketTimeoutException e) {
if (timeoutCount >= maxTimeoutRetries_) {
throw e;
}
// didn't get an ack for this data. need to resend
// it.
timeoutCount++;
transferTftp_.bufferedSend(lastSentData);
continue;
}
}
if (answer == null || !(answer instanceof TFTPAckPacket)) {
if (!shutdownTransfer) {
logError_
.println("Unexpected response from tftp client during transfer ("
+ answer + "). Transfer aborted.");
}
break;
} else {
// once we get here, we know we have an answer packet
// from the correct host.
TFTPAckPacket ack = (TFTPAckPacket) answer;
if (ack.getBlockNumber() != block) {
/*
* The origional tftp spec would have called on us to resend the
* previous data here, however, that causes the SAS Syndrome.
* http://www.faqs.org/rfcs/rfc1123.html section 4.2.3.1 The modified
* spec says that we ignore a duplicate ack. If the packet was really
* lost, we will time out on receive, and resend the previous data at
* that point.
*/
sendNext = false;
} else {
// send the next block
block++;
if (block > 65535) {
// wrap the block number
block = 0;
}
sendNext = true;
}
}
}
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
// noop
}
}
}
/*
* handle a tftp write request.
*/
private void handleWrite(TFTPWriteRequestPacket twrp) throws IOException,
TFTPPacketException {
OutputStream bos = null;
try {
if (mode_ == ServerMode.GET_ONLY) {
transferTftp_.bufferedSend(new TFTPErrorPacket(twrp.getAddress(), twrp
.getPort(), TFTPErrorPacket.ILLEGAL_OPERATION,
"Write not allowed by server."));
return;
}
int lastBlock = 0;
String fileName = twrp.getFilename();
try {
File temp = buildSafeFile(serverWriteDirectory_, fileName, true);
//if file exists, overwrite
/*if (temp.exists()) {
transferTftp_.bufferedSend(new TFTPErrorPacket(twrp.getAddress(), twrp
.getPort(), TFTPErrorPacket.FILE_EXISTS, "File already exists"));
return;
}*/
bos = new BufferedOutputStream(new FileOutputStream(temp,false));
if (twrp.getMode() == TFTP.NETASCII_MODE) {
bos = new FromNetASCIIOutputStream(bos);
}
} catch (Exception e) {
transferTftp_.bufferedSend(new TFTPErrorPacket(twrp.getAddress(), twrp
.getPort(), TFTPErrorPacket.UNDEFINED, e.getMessage()));
return;
}
TFTPAckPacket lastSentAck = new TFTPAckPacket(twrp.getAddress(), twrp.getPort(), 0);
transferTftp_.bufferedSend(lastSentAck);
while (true) {
// get the response - ensure it is from the right place.
TFTPPacket dataPacket = null;
int timeoutCount = 0;
while (!shutdownTransfer
&& (dataPacket == null
|| !dataPacket.getAddress().equals(twrp.getAddress()) || dataPacket
.getPort() != twrp.getPort())) {
// listen for an answer.
if (dataPacket != null) {
// The data that we got didn't come from the
// expected source, fire back an error, and continue
// listening.
log_.println("TFTP Server ignoring message from unexpected source.");
transferTftp_.bufferedSend(new TFTPErrorPacket(dataPacket.getAddress(),
dataPacket.getPort(), TFTPErrorPacket.UNKNOWN_TID,
"Unexpected Host or Port"));
}
try {
dataPacket = transferTftp_.bufferedReceive();
} catch (SocketTimeoutException e) {
if (timeoutCount >= maxTimeoutRetries_) {
throw e;
}
// It didn't get our ack. Resend it.
transferTftp_.bufferedSend(lastSentAck);
timeoutCount++;
continue;
}
}
if (dataPacket != null && dataPacket instanceof TFTPWriteRequestPacket) {
// it must have missed our initial ack. Send another.
lastSentAck = new TFTPAckPacket(twrp.getAddress(), twrp.getPort(), 0);
transferTftp_.bufferedSend(lastSentAck);
} else if (dataPacket == null || !(dataPacket instanceof TFTPDataPacket)) {
if (!shutdownTransfer) {
logError_
.println("Unexpected response from tftp client during transfer ("
+ dataPacket + "). Transfer aborted.");
}
break;
} else {
int block = ((TFTPDataPacket) dataPacket).getBlockNumber();
byte[] data = ((TFTPDataPacket) dataPacket).getData();
int dataLength = ((TFTPDataPacket) dataPacket).getDataLength();
int dataOffset = ((TFTPDataPacket) dataPacket).getDataOffset();
if (block > lastBlock || (lastBlock == 65535 && block == 0)) {
// it might resend a data block if it missed our ack
// - don't rewrite the block.
bos.write(data, dataOffset, dataLength);
lastBlock = block;
}
lastSentAck = new TFTPAckPacket(twrp.getAddress(), twrp.getPort(), block);
transferTftp_.bufferedSend(lastSentAck);
if (dataLength < TFTPDataPacket.MAX_DATA_LENGTH) {
// end of stream signal - The tranfer is complete.
bos.close();
// But my ack may be lost - so listen to see if I
// need to resend the ack.
for (int i = 0; i < maxTimeoutRetries_; i++) {
try {
dataPacket = transferTftp_.bufferedReceive();
} catch (SocketTimeoutException e) {
// this is the expected route - the client
// shouldn't be sending any more packets.
break;
}
if (dataPacket != null
&& (!dataPacket.getAddress().equals(twrp.getAddress()) || dataPacket
.getPort() != twrp.getPort())) {
// make sure it was from the right client...
transferTftp_
.bufferedSend(new TFTPErrorPacket(dataPacket
.getAddress(), dataPacket.getPort(),
TFTPErrorPacket.UNKNOWN_TID,
"Unexpected Host or Port"));
} else {
// This means they sent us the last
// datapacket again, must have missed our
// ack. resend it.
transferTftp_.bufferedSend(lastSentAck);
}
}
// all done.
break;
}
}
}
} finally {
if (bos != null) {
bos.close();
}
}
}
/*
* Utility method to make sure that paths provided by tftp clients do not get outside of the
* serverRoot directory.
*/
private File buildSafeFile(File serverDirectory, String fileName, boolean createSubDirs)
throws IOException {
File temp = new File(serverDirectory, fileName);
temp = temp.getCanonicalFile();
if (!isSubdirectoryOf(serverDirectory, temp)) {
throw new IOException("Cannot access files outside of tftp server root.");
}
// ensure directory exists (if requested)
if (createSubDirs) {
createDirectory(temp.getParentFile());
}
return temp;
}
/*
* recursively create subdirectories
*/
private void createDirectory(File file) throws IOException {
File parent = file.getParentFile();
if (parent == null) {
throw new IOException("Unexpected error creating requested directory");
}
if (!parent.exists()) {
// recurse...
createDirectory(parent);
}
if (parent.isDirectory()) {
if (file.isDirectory()) {
return;
}
boolean result = file.mkdir();
if (!result) {
throw new IOException("Couldn't create requested directory");
}
} else {
throw new IOException(
"Invalid directory path - file in the way of requested folder");
}
}
/*
* recursively check to see if one directory is a parent of another.
*/
private boolean isSubdirectoryOf(File parent, File child) {
File childsParent = child.getParentFile();
if (childsParent == null) {
return false;
}
if (childsParent.equals(parent)) {
return true;
} else {
return isSubdirectoryOf(parent, childsParent);
}
}
}
/**
* Set the stream object to log debug / informational messages. By default, this is a no-op
*
* @param log
*/
public void setLog(PrintStream log) {
this.log_ = log;
}
/**
* Set the stream object to log error messsages. By default, this is a no-op
*
* @param logError
*/
public void setLogError(PrintStream logError) {
this.logError_ = logError;
}
}
==========================================================================
3、包装server实现
package com.wolf.tftp.server;
import java.io.*;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-6
* Time: 下午12:43
* To change this template use File | Settings | File Templates.
*/
public class TFTPServerConsole {
private TFTPServer server;
private String serverReadDir;
private String serverWriteDir;
private int port;
private int timeout = 30000;
private TFTPServer.ServerMode serverMode;
//single instance
private volatile static TFTPServerConsole console;
private TFTPServerConsole() throws Exception {
//set default value;
serverReadDir = SERVER_READ_DIR;
serverWriteDir = SERVER_WRITE_DIR;
port = DEFAULT_TFTP_PORT;
serverMode = TFTPServer.ServerMode.GET_AND_PUT;
server = new TFTPServer(new File(serverReadDir), new File(serverWriteDir), port, serverMode,
null, null);
server.setSocketTimeout(timeout);
}
public static TFTPServerConsole getInstance() throws Exception {
if (console == null) {
synchronized (Object.class) {
if (console == null) {
console = new TFTPServerConsole();
}
}
}
return console;
}
public void startServer() {
try {
if (server != null && !server.isRunning()) {
server.launch();
} else {
System.out.println("TFTP server has been running already!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void stopServer() {
try {
if (server != null && server.isRunning()) {
server.shutdown();
System.out.println("TFTP Server shutdown.");
} else {
System.out.println("TFTP server is not running");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setServerReadDir(String serverReadDir) {
this.serverReadDir = serverReadDir;
}
public void setServerWriteDir(String serverWriteDir) {
this.serverWriteDir = serverWriteDir;
}
public void setPort(int port) {
this.port = port;
}
public void setServerMode(TFTPServer.ServerMode serverMode) {
this.serverMode = serverMode;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
==========================================================================
4、客户端工作器
package com.wolf.tftp.client;
import org.apache.commons.net.tftp.TFTP;
import org.apache.commons.net.tftp.TFTPClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-7
* Time: 上午11:02
* To change this template use File | Settings | File Templates.
*/
public class TFTPClientWorker {
private final String host;
private final int port;
private final boolean isReceive;
private final int transferMode;
private final String localFilename;
private final String remoteFilename;
/**
* TFTPClientTask Builder
*/
public static class TFTPClientWorkerBuilder {
private String host = "localhost";
private int port = DEFAULT_TFTP_PORT;
private boolean isReceive;
private int mode = TFTP.BINARY_MODE;// or TFTP.ASCII_MODE
private String localFilename;
private String remoteFilename;
public TFTPClientWorkerBuilder host(String host) {
this.host = host;
return this;
}
public TFTPClientWorkerBuilder port(int port) {
this.port = port;
return this;
}
public TFTPClientWorkerBuilder isReceive(boolean isReceiver) {
this.isReceive = isReceiver;
return this;
}
public TFTPClientWorkerBuilder mode(int mode) {
this.mode = mode;
return this;
}
public TFTPClientWorkerBuilder localFilename(String localFilename) {
this.localFilename = localFilename;
return this;
}
public TFTPClientWorkerBuilder remoteFilename(String remoteFilename) {
this.remoteFilename = remoteFilename;
return this;
}
public TFTPClientWorker builder() {
return new TFTPClientWorker(this);
}
}
private TFTPClientWorker(TFTPClientWorkerBuilder builder) {
host = builder.host;
port = builder.port;
isReceive = builder.isReceive;
transferMode = builder.mode;
localFilename = builder.localFilename;
remoteFilename = builder.remoteFilename;
}
public String getHost() {
return host;
}
public boolean isReceive() {
return isReceive;
}
public int getTransferMode() {
return transferMode;
}
public String getLocalFilename() {
return localFilename;
}
public String getRemoteFilename() {
return remoteFilename;
}
/**
*
* @return the File path in TFTP server
* @throws SocketException
*/
public String doJob() throws SocketException{
TFTPClient tftp = new TFTPClient();
// We want to timeout if a response takes longer than 60 seconds
tftp.setDefaultTimeout(60000);
// Open local socket
try {
tftp.open();
} catch (SocketException e) {
System.err.println("Error: could not open local UDP socket.");
System.err.println(e.getMessage());
throw e;
}
if (isReceive) {
received(tftp);
return SERVER_WRITE_DIR.endsWith(File.separator)?
SERVER_WRITE_DIR + remoteFilename:
SERVER_WRITE_DIR + File.separator + remoteFilename;
} else {
send(tftp);
return SERVER_READ_DIR.endsWith(File.separator)?
SERVER_READ_DIR + remoteFilename:
SERVER_READ_DIR + File.separator + remoteFilename;
}
}
private void received(TFTPClient tftp) {
FileOutputStream output = null;
File file = new File(localFilename);
// Try to open local file for writing
try {
// If file exists, overwrite it.
output = new FileOutputStream(file,false);
} catch (IOException e) {
tftp.close();
System.err.println("Error: could not open local file for writing.");
System.err.println(e.getMessage());
return;
}
// Try to receive remote file via TFTP
try {
tftp.receiveFile(remoteFilename, transferMode, output, host,port);
} catch (UnknownHostException e) {
System.err.println("Error: could not resolve hostname.");
System.err.println(e.getMessage());
return;
} catch (IOException e) {
System.err.println(
"Error: I/O exception occurred while receiving file.");
System.err.println(e.getMessage());
return;
} finally {
// Close local socket and output file
tftp.close();
try {
if (output != null) {
output.close();
}
//closed = true;
} catch (IOException e) {
//closed = false;
System.err.println("Error: error closing file.");
System.err.println(e.getMessage());
}
}
}
private void send(TFTPClient tftp) {
// We're sending a file
FileInputStream input = null;
// Try to open local file for reading
try {
input = new FileInputStream(localFilename);
} catch (IOException e) {
tftp.close();
System.err.println("Error: could not open local file for reading.");
System.err.println(e.getMessage());
return;
}
// Try to send local file via TFTP
try {
tftp.sendFile(remoteFilename, transferMode, input, host, port);
} catch (UnknownHostException e) {
System.err.println("Error: could not resolve hostname.");
System.err.println(e.getMessage());
return;
} catch (IOException e) {
System.err.println(
"Error: I/O exception occurred while sending file.");
System.err.println(e.getMessage());
return;
} finally {
// Close local socket and input file
tftp.close();
try {
if (input != null) {
input.close();
}
//closed = true;
} catch (IOException e) {
//closed = false;
System.err.println("Error: error closing file.");
System.err.println(e.getMessage());
}
}
}
}
==========================================================================
5、公共常量类
package com.wolf.tftp.common;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-7
* Time: 上午11:00
* To change this template use File | Settings | File Templates.
*/
public abstract class Constants {
public static final int DEFAULT_TFTP_PORT = 69;
public static final String SERVER_READ_DIR;
public static final String SERVER_WRITE_DIR;
static {
SERVER_READ_DIR = System.getProperty("tftp.server.read_dir",System.getProperty("java.io.tmpdir"));
SERVER_WRITE_DIR = System.getProperty("tftp.server.write_dir",System.getProperty("java.io.tmpdir"));
}
}
==========================================================================
6、测试,可以测试并发时的性能
启动tftp server
package com.wolf.tftp.test;
import com.wolf.tftp.server.TFTPServer;
import com.wolf.tftp.server.TFTPServerConsole;
import java.io.*;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-6
* Time: 下午12:43
* To change this template use File | Settings | File Templates.
*/
public class TFTPServerConsoleTest {
private final static String WRITE_PATH = "E:\\tftp";
private final static String READ_PATH = "E:\\tftp";
private final static String LOG_FILE="e:\\log\\tftp.log";
private final static String LOG_ERROR_FILE="e:\\log\\tftp.err";
public static void main(String[] args) throws Exception {
TFTPServerConsole console = TFTPServerConsole.getInstance();
console.startServer();
System.out.println("TFTP Server running. Press enter to stop.");
new InputStreamReader(System.in).read();
console.stopServer();
System.exit(0);
}
public void startServer() throws Exception {
{
PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(LOG_FILE)));
PrintStream err = new PrintStream(new BufferedOutputStream(new FileOutputStream(LOG_ERROR_FILE)));
TFTPServer ts = new TFTPServer(new File(READ_PATH), new File(WRITE_PATH),6900, TFTPServer.ServerMode.GET_AND_PUT,
out,err );
ts.setSocketTimeout(2000);
System.out.println("TFTP Server running. Press enter to stop.");
new InputStreamReader(System.in).read();
ts.shutdown();
System.out.println("Server shut down.");
System.exit(0);
}
}
}
客户端调用
package com.wolf.tftp.test;
import org.apache.commons.net.tftp.TFTP;
import java.util.Random;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-6
* Time: 下午2:18
* To change this template use File | Settings | File Templates.
*/
public class TFTPClientConsoleTest {
static final String USAGE =
"Usage: tftp [options] hostname localfile remotefile\n\n" +
"hostname - The name of the remote host\n" +
"localfile - The name of the local file to send or the name to use for\n" +
"\tthe received file\n" +
"remotefile - The name of the remote file to receive or the name for\n" +
"\tthe remote server to use to name the local file being sent.\n\n" +
"options: (The default is to assume -r -b)\n" +
"\t-s Send a local file\n" +
"\t-r Receive a remote file\n" +
"\t-a Use ASCII transfer mode\n" +
"\t-b Use binary transfer mode\n";
private final static int CLIENT_COUNT = 200;
private final static int DURATION = 300;
private final static String TASK_PREFIX = "TFTP-client-";
public static void main(String[] args) {
int argc = 0;
String arg = "";
boolean receiveFile = false;
int transferMode = TFTP.ASCII_MODE;
String hostname, localFilename = "", remoteFilename = "";
// Parse options
for (argc = 0; argc < args.length; argc++) {
arg = args[argc];
if (arg.startsWith("-")) {
if (arg.equals("-r")) {
receiveFile = true;
} else if (arg.equals("-s")) {
receiveFile = false;
} else if (arg.equals("-a")) {
transferMode = TFTP.ASCII_MODE;
} else if (arg.equals("-b")) {
transferMode = TFTP.BINARY_MODE;
} else {
System.err.println("Error: unrecognized option.");
System.err.print(USAGE);
System.exit(1);
}
} else {
break;
}
}
// Make sure there are enough arguments
if (args.length - argc < 2 || args.length - argc > 3) {
System.err.println("Error: invalid number of arguments.");
System.err.print(USAGE);
System.exit(1);
}
// Get host and file arguments
hostname = args[argc];
if (args.length - argc == 2) {
localFilename = remoteFilename = args[argc + 1];
}
if (args.length - argc == 3) {
localFilename = args[argc + 1];
remoteFilename = args[argc + 2];
}
TaskSchedule schedule = new TaskSchedule(DURATION, CLIENT_COUNT);
for (int i = 0; i < CLIENT_COUNT; i++) {
String taskId = TASK_PREFIX + i;
Random random = new Random();
//取1-500之间的正整数
int temp = random.nextInt(SOURCE_FILE_COUNT);
localFilename = SOURCE_FILE_DIR + PREFIX + temp;
//remoteFilename = taskId + PREFIX + System.currentTimeMillis();
remoteFilename = PREFIX + temp;
TFTPClientTask task = new TFTPClientTask.TFTPClientTaskBuilder(taskId)
.host(hostname)
.isReceive(receiveFile)
.localFilename(localFilename)
.remoteFilename(remoteFilename)
.mode(transferMode)
.barrier(schedule.cyclicBarrier)
.builder();
schedule.schedule(task);
}
}
private final static String SOURCE_FILE_DIR = "D:\\work\\documents\\tftp-test-file\\";
private final static String PREFIX = "CiscoConfig-";
//upload file count + 1
private final static int SOURCE_FILE_COUNT = 501;
}
package com.wolf.tftp.test;
import java.util.concurrent.CyclicBarrier;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-7
* Time: 上午10:39
* To change this template use File | Settings | File Templates.
*/
public abstract class AbstractTask implements Runnable {
String taskId;
long successTimes;
long failTimes;
static long totalTimes;
static CyclicBarrier cyclicBarrier;
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public long getSuccessTimes() {
return successTimes;
}
public void setSuccessTimes(long successTimes) {
this.successTimes = successTimes;
}
public long getFailTimes() {
return failTimes;
}
public void setFailTimes(long failTimes) {
this.failTimes = failTimes;
}
public long getTotalTimes() {
return totalTimes;
}
public void setTotalTimes(long totalTimes) {
this.totalTimes = totalTimes;
}
public CyclicBarrier getCyclicBarrier() {
return cyclicBarrier;
}
public void setCyclicBarrier(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
}
package com.wolf.tftp.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-7
* Time: 上午9:18
* To change this template use File | Settings | File Templates.
*/
public class TaskSchedule<T extends AbstractTask> {
CyclicBarrier cyclicBarrier;
long begin = System.currentTimeMillis();
List<T> tasks = new ArrayList<T>();
ExecutorService executor = Executors.newCachedThreadPool();
public TaskSchedule(final long duration, int taskCount) {
System.out.println("TFTP client task is running...");
System.out.println("Total task : " + taskCount);
System.out.println("Time of duration :" + duration + "s");
cyclicBarrier = new CyclicBarrier(taskCount, new Runnable() {
@Override
public void run() {
long times = 0L;
long successTimes = 0L;
while (System.currentTimeMillis() - begin > duration * 1000) {
for (AbstractTask task : tasks) {
times = task.getTotalTimes();
successTimes += task.getSuccessTimes();
System.out.println("==============================================================");
//System.out.println(task.getTaskId() + " execute total times is: " + task.getTotalTimes());
System.out.println(task.getTaskId() + " execute success times is: " + task.getSuccessTimes());
System.out.println(task.getTaskId() + " execute fail times is: " + task.getFailTimes());
//System.out.println(task.getTaskId() + " execute rate is: " + task.getTotalTimes() / duration + "times/s");
System.out.println("==============================================================");
}
System.out.println("All of " + tasks.size() + " tasks execute TFTP transfer file task total count is : " + times);
System.out.println("Execute success rate is: " + successTimes / duration + " times/s");
executor.shutdown();
return;
}
System.out.println("Task is execute...");
}
});
}
public void schedule(T task) {
tasks.add(task);
executor.execute(task);
}
}
package com.wolf.tftp.test;
import com.wolf.tftp.client.TFTPClientWorker;
import com.wolf.tftp.common.Constants;
import org.apache.commons.net.tftp.TFTP;
import java.net.SocketException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* Created with IntelliJ IDEA.
* User: jiyanbin
* Date: 13-8-6
* Time: 下午1:27
* To change this template use File | Settings | File Templates.
*/
public class TFTPClientTask extends AbstractTask {
final TFTPClientWorker worker;
/**
* TFTPClientTask Builder
*/
public static class TFTPClientTaskBuilder {
private final String taskId;
private String host = "localhost";
private int port = Constants.DEFAULT_TFTP_PORT;
private boolean isReceive;
private int mode = TFTP.BINARY_MODE;// or TFTP.ASCII_MODE
private String localFilename;
private String remoteFilename;
private CyclicBarrier barrier;
public TFTPClientTaskBuilder(String taskId) {
this.taskId = taskId;
}
public TFTPClientTaskBuilder host(String host) {
this.host = host;
return this;
}
public TFTPClientTaskBuilder port(int port) {
this.port = port;
return this;
}
public TFTPClientTaskBuilder isReceive(boolean isReceiver) {
this.isReceive = isReceiver;
return this;
}
public TFTPClientTaskBuilder mode(int mode) {
this.mode = mode;
return this;
}
public TFTPClientTaskBuilder localFilename(String localFilename) {
this.localFilename = localFilename;
return this;
}
public TFTPClientTaskBuilder remoteFilename(String remoteFilename) {
this.remoteFilename = remoteFilename;
return this;
}
public TFTPClientTaskBuilder barrier(CyclicBarrier barrier) {
this.barrier = barrier;
return this;
}
public TFTPClientTask builder() {
return new TFTPClientTask(this);
}
}
private TFTPClientTask(TFTPClientTaskBuilder builder) {
TFTPClientWorker.TFTPClientWorkerBuilder jobBuilder = new TFTPClientWorker.TFTPClientWorkerBuilder();
jobBuilder.host(builder.host)
.port(builder.port)
.isReceive(builder.isReceive)
.mode(builder.mode)
.localFilename(builder.localFilename)
.remoteFilename(builder.remoteFilename);
worker = jobBuilder.builder();
taskId = builder.taskId;
cyclicBarrier = builder.barrier;
}
public TFTPClientWorker getWorker() {
return worker;
}
public void run() {
try {
while (!Thread.interrupted()) {
//System.out.println("Task :" + taskId + "is executing...");
totalTimes++;
String filePath = worker.doJob();
//System.out.println("Remote file path is : " + filePath);
successTimes++;
cyclicBarrier.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
failTimes++;
} catch (BrokenBarrierException e) {
e.printStackTrace();
failTimes++;
} catch (SocketException e) {
System.err.println("Error: could not open local UDP socket.");
System.err.println(e.getMessage());
failTimes++;
}
}
}
相关推荐
在本文中,我们将深入探讨如何使用Apache Commons Net库中的FTP客户端类来实现FTP文件传输操作。首先,我们需要理解FTP的基本概念。 FTP是一种应用层协议,用于在互联网上进行文件传输。它允许用户从远程服务器上传...
在Apache Atlas 2.1.0版本中,服务器组件的压缩包`apache-atlas-2.1.0-server.tar.gz`提供了一个核心的服务框架,用于构建和维护数据治理解决方案,但值得注意的是,这个版本不含HBase和Solr这两个关键组件。...
在"apache-atlas-2.1.0-server.tar.gz"压缩包中,包含了Apache Atlas 2.1.0服务器的所有组件和配置文件。解压后,通常会包含以下部分: 1. **bin** 目录:存放启动和停止Apache Atlas服务器的脚本。 2. **conf** ...
这个压缩包 "apache-atlas-2.0.0-server.tar.gz" 包含了 Atlas 的 2.0.0 版本服务器端的所有组件,可以用于在生产环境中部署。用户如果需要内嵌HBase和Solr的功能,可以通过联系提供者来获取。 Apache Atlas 在数据...
用于压缩/解压缩的java开发工具包,基本上主流格式全包含,其中apache-common-compress内有5个jar包,两个是test的不用管,剩余三个,一个是源码包,一个是开发包另一个是javadoc。解压除RAR外的所有格式。 apache-...
这个压缩包“apache-atlas-2.2.0-server.tar.gz”包含了Apache Atlas服务器的所有组件,用于搭建一个完整的内嵌式安装环境。 Apache Atlas的核心功能包括: 1. **元数据管理**:Apache Atlas提供了强大的元数据...
这样可以利用Apache的高并发处理能力,同时利用WebLogic Server的高级Java EE功能。 **Apache HTTP Server 2.2和2.4**: Apache HTTP Server是世界上最流行的开源Web服务器软件,其2.2和2.4版本代表了两个主要的...
标签:server、codec、apache、apacheds、kerberos、directory、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和...
基于Apache Common-net 的 TFTP Server, 通过了测试,支持大文件,java版的TFTP Server 不好找,网上存有一个Tftp4java 0.8 版的,存在bug,只支持32M以下的文件,主要原因是开发者对FTTP传输的处理规则不清楚,所以...
使用apache commons-net包实现文件ftp上传
apache-jmeter-5.6.3.zip apache-jmeter-5.6.3.tgz apache-jmeter-5.6.3_src.zip apache-jmeter-5.6.3_src.tgz
Apache Tomcat 软件是Jakarta Servlet、 Jakarta Server Pages、 Jakarta Expression Language、 Jakarta WebSocket、 Jakarta Annotations和 Jakarta Authentication 规范的开源实现 。 压缩包内容: apache-...
Maven坐标:org.apache.hadoop:hadoop-yarn-server-common:2.6.5; 标签:server、apache、common、hadoop、yarn、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可...
apache-atlas-1.1.0-server.tar.gz apache-atlas-1.1.0-falcon-hook.tar.gz apache-atlas-1.1.0-sources.tar.gz apache-atlas-1.1.0-hbase-hook.tar.gz apache-atlas-1.1.0-sqoop-hook.tar.gz apache-atlas-1.1.0-...
Maven坐标:org.apache.flink:flink-table-common:1.12.7; 标签:apache、flink、table、common、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
Maven坐标:org.apache.hadoop:hadoop-yarn-server-common:2.5.1; 标签:apache、hadoop、yarn、server、common、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可...
Maven坐标:org.apache.parquet:parquet-common:1.10.0; 标签:apache、common、parquet、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...