一、前言
基于apache的commons-net开源包中的org.apache.commons.net.tftp.TFTPClient、org.apache.commons.net.tftp.TFTP类,实现了基于tftp文件传输协议的客户端调用访问,详情参见下面源码说明。
二、源码说明
1.TFTPClient类
package org.apache.commons.net.tftp;@b@@b@import java.io.IOException;@b@import java.io.InputStream;@b@import java.io.InterruptedIOException;@b@import java.io.OutputStream;@b@import java.net.InetAddress;@b@import java.net.SocketException;@b@import java.net.UnknownHostException;@b@import org.apache.commons.net.io.FromNetASCIIOutputStream;@b@import org.apache.commons.net.io.ToNetASCIIInputStream;@b@@b@public class TFTPClient extends TFTP@b@{@b@ public static final int DEFAULT_MAX_TIMEOUTS = 5;@b@ private int __maxTimeouts;@b@@b@ public TFTPClient()@b@ {@b@ this.__maxTimeouts = 5;@b@ }@b@@b@ public void setMaxTimeouts(int numTimeouts)@b@ {@b@ if (numTimeouts < 1)@b@ this.__maxTimeouts = 1;@b@ else@b@ this.__maxTimeouts = numTimeouts;@b@ }@b@@b@ public int getMaxTimeouts()@b@ {@b@ return this.__maxTimeouts;@b@ }@b@@b@ public int receiveFile(String filename, int mode, OutputStream output, InetAddress host, int port)@b@ throws IOException@b@ {@b@ int bytesRead;@b@ int lastBlock;@b@ int hostPort;@b@ TFTPPacket received = null;@b@@b@ TFTPAckPacket ack = new TFTPAckPacket(host, port, 0);@b@@b@ beginBufferedOps();@b@@b@ int dataLength = lastBlock = hostPort = bytesRead = 0;@b@ int block = 1;@b@@b@ if (mode == 0)@b@ output = new FromNetASCIIOutputStream(output);@b@@b@ TFTPPacket sent = new TFTPReadRequestPacket(host, port, filename, mode);@b@ do@b@ {@b@ bufferedSend(sent);@b@ do@b@ {@b@ int timeouts = 0;@b@ if (timeouts < this.__maxTimeouts)@b@ {@b@ try@b@ {@b@ received = bufferedReceive();@b@ }@b@ catch (SocketException e)@b@ {@b@ while (true)@b@ if (++timeouts >= this.__maxTimeouts)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Connection timed out.");@b@ }@b@ }@b@ catch (InterruptedIOException e)@b@ {@b@ while (true)@b@ if (++timeouts >= this.__maxTimeouts)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Connection timed out.");@b@ }@b@@b@ }@b@ catch (TFTPPacketException e)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Bad packet: " + e.getMessage());@b@ }@b@@b@ }@b@@b@ if (lastBlock == 0)@b@ {@b@ hostPort = received.getPort();@b@ ack.setPort(hostPort);@b@ if (!(host.equals(received.getAddress())))@b@ {@b@ host = received.getAddress();@b@ ack.setAddress(host);@b@ sent.setAddress(host);@b@ }@b@@b@ }@b@@b@ if ((!(host.equals(received.getAddress()))) || (received.getPort() != hostPort)) {@b@ break label485;@b@ }@b@@b@ switch (received.getType())@b@ {@b@ case 5:@b@ error = (TFTPErrorPacket)received;@b@ endBufferedOps();@b@ throw new IOException("Error code " + error.getError() + " received: " + error.getMessage());@b@ case 3:@b@ TFTPDataPacket data = (TFTPDataPacket)received;@b@ dataLength = data.getDataLength();@b@@b@ lastBlock = data.getBlockNumber();@b@@b@ if (lastBlock == block)@b@ {@b@ try@b@ {@b@ output.write(data.getData(), data.getDataOffset(), dataLength);@b@ }@b@ catch (IOException e)@b@ {@b@ error = new TFTPErrorPacket(host, hostPort, 3, "File write failed.");@b@@b@ bufferedSend(error);@b@ endBufferedOps();@b@ throw e;@b@ }@b@ ++block;@b@ if (block <= 65535)@b@ break label516;@b@@b@ block = 0; break label516:@b@ }@b@@b@ discardPackets(); }@b@ }@b@ while (lastBlock != ((block == 0) ? 65535 : block - 1));@b@ continue;@b@@b@ endBufferedOps();@b@ throw new IOException("Received unexpected packet type.");@b@@b@ label485: TFTPErrorPacket error = new TFTPErrorPacket(received.getAddress(), received.getPort(), 5, "Unexpected host or port.");@b@@b@ bufferedSend(error);@b@ continue;@b@@b@ label516: ack.setBlockNumber(lastBlock);@b@ sent = ack;@b@ bytesRead += dataLength;@b@ }@b@@b@ while (dataLength == 512);@b@@b@ bufferedSend(sent);@b@ endBufferedOps();@b@@b@ return bytesRead;@b@ }@b@@b@ public int receiveFile(String filename, int mode, OutputStream output, String hostname, int port)@b@ throws UnknownHostException, IOException@b@ {@b@ return receiveFile(filename, mode, output, InetAddress.getByName(hostname), port);@b@ }@b@@b@ public int receiveFile(String filename, int mode, OutputStream output, InetAddress host)@b@ throws IOException@b@ {@b@ return receiveFile(filename, mode, output, host, 69);@b@ }@b@@b@ public int receiveFile(String filename, int mode, OutputStream output, String hostname)@b@ throws UnknownHostException, IOException@b@ {@b@ return receiveFile(filename, mode, output, InetAddress.getByName(hostname), 69);@b@ }@b@@b@ public void sendFile(String filename, int mode, InputStream input, InetAddress host, int port)@b@ throws IOException@b@ {@b@ int bytesRead;@b@ int lastBlock;@b@ int hostPort;@b@ int totalThisPacket;@b@ TFTPPacket received = null;@b@@b@ TFTPDataPacket data = new TFTPDataPacket(host, port, 0, this._sendBuffer, 4, 0);@b@@b@ boolean justStarted = true;@b@@b@ beginBufferedOps();@b@@b@ int dataLength = lastBlock = hostPort = bytesRead = totalThisPacket = 0;@b@ int block = 0;@b@ boolean lastAckWait = false;@b@@b@ if (mode == 0)@b@ input = new ToNetASCIIInputStream(input);@b@@b@ TFTPPacket sent = new TFTPWriteRequestPacket(host, port, filename, mode);@b@ do@b@ {@b@ bufferedSend(sent);@b@ do@b@ {@b@ int timeouts = 0;@b@ if (timeouts < this.__maxTimeouts)@b@ {@b@ try@b@ {@b@ received = bufferedReceive();@b@ }@b@ catch (SocketException e)@b@ {@b@ while (true)@b@ if (++timeouts >= this.__maxTimeouts)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Connection timed out.");@b@ }@b@ }@b@ catch (InterruptedIOException e)@b@ {@b@ while (true)@b@ if (++timeouts >= this.__maxTimeouts)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Connection timed out.");@b@ }@b@@b@ }@b@ catch (TFTPPacketException e)@b@ {@b@ endBufferedOps();@b@ throw new IOException("Bad packet: " + e.getMessage());@b@ }@b@@b@ }@b@@b@ if (justStarted)@b@ {@b@ justStarted = false;@b@ hostPort = received.getPort();@b@ data.setPort(hostPort);@b@ if (!(host.equals(received.getAddress())))@b@ {@b@ host = received.getAddress();@b@ data.setAddress(host);@b@ sent.setAddress(host);@b@ }@b@@b@ }@b@@b@ if ((!(host.equals(received.getAddress()))) || (received.getPort() != hostPort)) {@b@ break label453;@b@ }@b@@b@ switch (received.getType())@b@ {@b@ case 5:@b@ error = (TFTPErrorPacket)received;@b@ endBufferedOps();@b@ throw new IOException("Error code " + error.getError() + " received: " + error.getMessage());@b@ case 4:@b@ TFTPAckPacket ack = (TFTPAckPacket)received;@b@@b@ lastBlock = ack.getBlockNumber();@b@@b@ if (lastBlock == block)@b@ {@b@ ++block;@b@ if (block > 65535)@b@ {@b@ block = 0;@b@ }@b@ if (!(lastAckWait))@b@ break label484;@b@ break label586:@b@ }@b@@b@ discardPackets(); }@b@ }@b@ while (lastBlock != ((block == 0) ? 65535 : block - 1));@b@ continue;@b@@b@ endBufferedOps();@b@ throw new IOException("Received unexpected packet type.");@b@@b@ label453: TFTPErrorPacket error = new TFTPErrorPacket(received.getAddress(), received.getPort(), 5, "Unexpected host or port.");@b@@b@ bufferedSend(error);@b@ continue;@b@@b@ label484: dataLength = 512;@b@ int offset = 4;@b@ totalThisPacket = 0;@b@@b@ while (dataLength > 0) { if ((bytesRead = input.read(this._sendBuffer, offset, dataLength)) <= 0)@b@ break;@b@ offset += bytesRead;@b@ dataLength -= bytesRead;@b@ totalThisPacket += bytesRead;@b@ }@b@@b@ if (totalThisPacket < 512)@b@ {@b@ lastAckWait = true;@b@ }@b@ data.setBlockNumber(block);@b@ data.setData(this._sendBuffer, 4, totalThisPacket);@b@ sent = data;@b@ }@b@ while ((totalThisPacket > 0) || (lastAckWait));@b@@b@ label586: endBufferedOps();@b@ }@b@@b@ public void sendFile(String filename, int mode, InputStream input, String hostname, int port)@b@ throws UnknownHostException, IOException@b@ {@b@ sendFile(filename, mode, input, InetAddress.getByName(hostname), port);@b@ }@b@@b@ public void sendFile(String filename, int mode, InputStream input, InetAddress host)@b@ throws IOException@b@ {@b@ sendFile(filename, mode, input, host, 69);@b@ }@b@@b@ public void sendFile(String filename, int mode, InputStream input, String hostname)@b@ throws UnknownHostException, IOException@b@ {@b@ sendFile(filename, mode, input, InetAddress.getByName(hostname), 69);@b@ }@b@}
2.TFTP类
package org.apache.commons.net.tftp;@b@@b@import java.io.IOException;@b@import java.io.InterruptedIOException;@b@import java.net.DatagramPacket;@b@import java.net.DatagramSocket;@b@import java.net.SocketException;@b@import org.apache.commons.net.DatagramSocketClient;@b@@b@public class TFTP extends DatagramSocketClient@b@{@b@ public static final int ASCII_MODE = 0;@b@ public static final int NETASCII_MODE = 0;@b@ public static final int BINARY_MODE = 1;@b@ public static final int IMAGE_MODE = 1;@b@ public static final int OCTET_MODE = 1;@b@ public static final int DEFAULT_TIMEOUT = 5000;@b@ public static final int DEFAULT_PORT = 69;@b@ static final int PACKET_SIZE = 516;@b@ private byte[] __receiveBuffer;@b@ private DatagramPacket __receiveDatagram;@b@ private DatagramPacket __sendDatagram;@b@ byte[] _sendBuffer;@b@@b@ public static final String getModeName(int mode)@b@ {@b@ return TFTPRequestPacket._modeStrings[mode];@b@ }@b@@b@ public TFTP()@b@ {@b@ setDefaultTimeout(5000);@b@ this.__receiveBuffer = null;@b@ this.__receiveDatagram = null;@b@ }@b@@b@ public final void discardPackets()@b@ throws IOException@b@ {@b@ DatagramPacket datagram = new DatagramPacket(new byte[516], 516);@b@@b@ int to = getSoTimeout();@b@ setSoTimeout(1);@b@ try@b@ {@b@ this._socket_.receive(datagram);@b@ }@b@ catch (SocketException e)@b@ {@b@ break label42: } catch (InterruptedIOException e) {@b@ }@b@ label42: setSoTimeout(to);@b@ }@b@@b@ public final TFTPPacket bufferedReceive()@b@ throws IOException, InterruptedIOException, SocketException, TFTPPacketException@b@ {@b@ this.__receiveDatagram.setData(this.__receiveBuffer);@b@ this.__receiveDatagram.setLength(this.__receiveBuffer.length);@b@ this._socket_.receive(this.__receiveDatagram);@b@@b@ return TFTPPacket.newTFTPPacket(this.__receiveDatagram);@b@ }@b@@b@ public final void bufferedSend(TFTPPacket packet)@b@ throws IOException@b@ {@b@ this._socket_.send(packet._newDatagram(this.__sendDatagram, this._sendBuffer));@b@ }@b@@b@ public final void beginBufferedOps()@b@ {@b@ this.__receiveBuffer = new byte[516];@b@ this.__receiveDatagram = new DatagramPacket(this.__receiveBuffer, this.__receiveBuffer.length);@b@@b@ this._sendBuffer = new byte[516];@b@ this.__sendDatagram = new DatagramPacket(this._sendBuffer, this._sendBuffer.length);@b@ }@b@@b@ public final void endBufferedOps()@b@ {@b@ this.__receiveBuffer = null;@b@ this.__receiveDatagram = null;@b@ this._sendBuffer = null;@b@ this.__sendDatagram = null;@b@ }@b@@b@ public final void send(TFTPPacket packet)@b@ throws IOException@b@ {@b@ this._socket_.send(packet.newDatagram());@b@ }@b@@b@ public final TFTPPacket receive()@b@ throws IOException, InterruptedIOException, SocketException, TFTPPacketException@b@ {@b@ DatagramPacket packet = new DatagramPacket(new byte[516], 516);@b@@b@ this._socket_.receive(packet);@b@@b@ return TFTPPacket.newTFTPPacket(packet);@b@ }@b@}