TFTP 服务端、客户端如下:
比较直接,原理自己搜,基于UDP,直接复制就行,记得把IP地址换了。
TFTP Server端:
TFTPack.java:
import java.util.Arrays;
public final class TFTPack extends TFTPpacket {
protected TFTPack() {
}
public TFTPack(int blockNumber) {
this.length = 4;
this.message = new byte[this.length];
System.out.println("TFTPack ack packet created:" +blockNumber);
put(0, (short) 4);
put(2, (short) blockNumber);
System.out.println("Service receive data: " + Arrays.toString(message));
}
public int blockNumber() {
return get(2);
}
}
TFTPdata.java:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public final class TFTPdata extends TFTPpacket {
protected TFTPdata() {
}
public TFTPdata(int blockNumber, InputStream in) throws Exception {
System.out.println("Data packet created:" +blockNumber);
this.message = new byte[maxTftpPakLen];
if (in == null) {
put(0, (short) 5); // TODO
put(2, (short) blockNumber);
this.length = 4;
}
put(0, (short) 3); // TODO
put(2, (short) blockNumber);
System.out.println("TFTPdata: " + message + " blockNumber: " + blockNumber);
int len = in.read(this.message, 4, maxTftpData) + 4;
if (len == 3)
this.length = 4;
}
public int blockNumber() {
return get(2);
}
public void data(byte[] buffer) {
byte[] buffer1 = buffer; // TODO
buffer1 = new byte[this.length - 4];
for (int i = 0; i < this.length - 4; i++)
buffer1[i] = this.message[(i + 4)];
}
public int write(OutputStream out) throws IOException {
out.write(this.message, 4, this.length - 4);
return this.length - 4;
}
}
TFTPerror.java:
public final class TFTPerror extends TFTPpacket
{
protected TFTPerror()
{
}
public TFTPerror(int number, String message)
{
if (message != null) {
System.out.println( "TFTP error: " + message);
this.length = (4 + message.length() + 1);
this.message = new byte[this.length];
put(0, (short)5); //TODO
put(2, (short)number);
put(4, message, (byte)0); //TODO
}
}
public int number()
{
return get(2);
}
public String message() {
return get(4, (byte)0); //TODO
}
}
TftpException.java:
public class TftpException extends Exception {
TftpException() {
}
public TftpException(String s) {
super(s);
}
}
TFTPpacket.java:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;
public class TFTPpacket {
public static final int tftpPort = 69;
public static final int maxTftpPakLen = 516;
public static final int maxTftpData = 512;
protected static final short tftpRRQ = 1;
protected static final short tftpWRQ = 2;
protected static final short tftpDATA = 3;
protected static final short tftpACK = 4;
protected static final short tftpERROR = 5;
protected static final int opOffset = 0;
protected static final int fileOffset = 2;
protected static final int blkOffset = 2;
protected static final int dataOffset = 4;
protected static final int numOffset = 2;
protected static final int msgOffset = 4;
protected int length;
protected byte[] message;
protected InetAddress host;
protected int port;
public TFTPpacket() {
this.message = new byte[maxTftpPakLen];
this.length = maxTftpPakLen;
}
public static TFTPpacket receive(DatagramSocket sock) throws IOException {
TFTPpacket in = new TFTPpacket();
TFTPpacket retPak = null;
DatagramPacket inPak = new DatagramPacket(in.message, in.length);
sock.receive(inPak);
switch (in.get(0)) {
case 1:
retPak = new TFTPread();//RRQ
break;
case 2:
retPak = new TFTPwrite();//WRQ
break;
case 3:
retPak = new TFTPdata();
break;
case 4:
retPak = new TFTPack();
break;
case 5:
retPak = new TFTPerror();
}
if (retPak != null) {
retPak.message = in.message;
retPak.length = inPak.getLength();
retPak.host = inPak.getAddress();
retPak.port = inPak.getPort();
System.out.println("Data packet: " + Arrays.toString(in.message) + " length: " + inPak.getLength()
+ " host:" + inPak.getAddress() + " port: " + inPak.getPort());
}
return retPak;
}
public void send(InetAddress ip, DatagramSocket sock) throws IOException {
sock.send(new DatagramPacket(this.message, this.length, ip, tftpPort));
}
public void send(InetAddress ip, int p, DatagramSocket s) throws IOException {
s.send(new DatagramPacket(this.message, this.length, ip, p));
}
public InetAddress getAddress() {
return this.host;
}
public int getPort() {
return this.port;
}
public int getLength() {
return this.length;
}
protected void put(int at, short value) {
int atLocal = at;
this.message[(atLocal++)] = (byte) (value >>> 8);
this.message[atLocal] = (byte) (value % 256);
}
protected void put(int at, String value, byte del) {
System.arraycopy(value.getBytes(), 0, this.message, at, value.length());
this.message[(at + value.length())] = del;
}
protected int get(int at) {
return (this.message[at] & 0xFF) << 8 | this.message[(at + 1)] & 0xFF;
}
protected String get(int at, byte del) {
int atLocal = at;
StringBuffer result = new StringBuffer();
while (this.message[atLocal] != del)
result.append((char) this.message[(atLocal++)]);
return result.toString();
}
public String fileName() {
return null;
}
}
TFTPread.java(读操作,这个不是实际的读):
public final class TFTPread extends TFTPpacket {
byte zero = 0;
short opcode = 1;
private void initialize(String filename, String reqType) {
this.length = (2 + filename.length() + 1 + reqType.length() + 1);
this.message = new byte[this.length];
put(0, opcode);
put(2, filename, zero);
put(2 + filename.length() + 1, reqType, zero);
}
protected TFTPread() {
}
public TFTPread(String filename) {
initialize(filename, "octet");
}
public TFTPread(String filename, String reqType) {
initialize(filename, reqType);
}
public String fileName() {
return get(2, (byte) 0); //TODO
}
public String requestType() {
String fname = fileName();
return get(2 + fname.length() + 1, (byte) 0); //TODO
}
}
TFTPwrite.java(同样不是实际的写):
public final class TFTPwrite extends TFTPpacket {
private void initialize(String filename, String reqType) {
this.length = (2 + filename.length() + 1 + reqType.length() + 1);
this.message = new byte[this.length];
put(0, (short) 2);
put(2, filename, (byte) 0);
put(2 + filename.length() + 1, reqType, (byte) 0);
}
protected TFTPwrite() {
}
public TFTPwrite(String filename) {
initialize(filename, "octet");
}
public TFTPwrite(String filename, String reqType) {
initialize(filename, reqType);
}
public String fileName() {
return get(2, (byte) 0);
}
public String requestType() {
String fname = fileName();
return get(2 + fname.length() + 1, (byte) 0);
}
}
接下来是Server端实际的操作
TFTPServiceHandler.java:(重点服务端读写操作类)
import xxx.TFTPack;
import xxx.TFTPdata;
import xxx.TFTPerror;
import xxx.TFTPpacket;
import xxx.TFTPread;
import xxx.TFTPwrite;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
/**
* TFTP Server handler处理类
*
* @author: zhangyongtao
* @date: 2022/7/10
*/
public class TFTPServiceHandler implements Runnable {
protected DatagramSocket socket;
protected InetAddress ipAddress;
protected int port;
protected FileInputStream inputStream;
protected FileOutputStream outputStream;
protected String rootPath = "./";
private TFTPpacket request;
private int fileIsExists = -1;
public TFTPServiceHandler(TFTPread request, String tftpRootPath) {
try {
this.rootPath = tftpRootPath;
this.socket = new DatagramSocket();
this.socket.setSoTimeout(300000);//300s
this.ipAddress = request.getAddress();
this.port = request.getPort();
this.request = request;
} catch (Exception e) {
e.printStackTrace();
TFTPerror ePak = new TFTPerror(1, e.getMessage());
try {
ePak.send(this.ipAddress, this.port, this.socket);
} catch (Exception localException1) {
}
}
}
public TFTPServiceHandler(TFTPwrite request, String tftpRootPath) {
try {
this.rootPath = tftpRootPath;
this.socket = new DatagramSocket();
this.socket.setSoTimeout(300000);
this.ipAddress = request.getAddress();
this.port = request.getPort();
this.request = request;
} catch (Exception e) {
// e.printStackTrace();
System.out.println("In the constructor:" + e.getMessage());
TFTPerror ePak = new TFTPerror(1, e.getMessage());
try {
ePak.send(this.ipAddress, this.port, this.socket);
} catch (Exception localException1) {
}
}
}
@Override
public void run() {
initialization();
if (fileIsExists == 0) {
System.out.println("run service...");
service();
}
}
//初始化,分离读写请求
public void initialization() {
String fileName = null;
try {
fileName = this.request.fileName();
} catch (Exception e1) {
e1.printStackTrace();
}
File path = new File(this.rootPath);
if ((this.request instanceof TFTPread)) {
try {
if (!path.exists()) {
new File("tftpRoot").mkdir();
path.mkdir();
errorMessage("initialization Folder not found");
return;
}
String fileNameContent = new String(fileName.getBytes("GBK"), "iso-8859-1");
// String localFilePathContent = new String(fileName.getBytes(), 0, fileName.length(), "GBK");
// System.out.println("AAA " + fileNameContent + " - " );
File srcFile = new File(this.rootPath + "/" + fileNameContent);
System.out.println("initialization srcFile file path: " + srcFile.getAbsolutePath());
if ((srcFile.exists()) && (srcFile.isFile())
&& (srcFile.canRead())) {
this.inputStream = new FileInputStream(srcFile);
fileIsExists = 0;
return;
}
fileIsExists = 1;
errorMessage("initialization TFTPread: File not found and" +
" rootPath: " + srcFile.getAbsolutePath());
} catch (Exception e) {
errorMessage(e);
e.printStackTrace();
}
} else if ((this.request instanceof TFTPwrite))
try {
if (!path.exists()) {
new File("tftpRoot").mkdir();
path.mkdir();
}
// String fileNameContent = new String(fileName.getBytes("GBK"), "iso-8859-1");
// System.out.println("AAA " + fileNameContent + " - " );
File srcFile = new File(this.rootPath + "/" + fileName);
System.out.println("Write file:" + srcFile.getAbsolutePath());
if (srcFile.exists()) {
System.out.println(srcFile + " is exists!!!!");
errorMessage("service TFTPread: File not Found");
fileIsExists = 1;
} else {
System.out.println(srcFile + " not exists,start write to service");
this.outputStream = new FileOutputStream(srcFile);
fileIsExists = 0;
}
} catch (Exception e) {
errorMessage(e);
e.printStackTrace();
}
}
//实际读取与写入
public void service() {
System.out.println("service begin...");
int bytesRead = TFTPpacket.maxTftpPakLen;
if ((this.request instanceof TFTPread)) {
try {
System.out.println("service request is TFTPread");
TFTPdata outPak = new TFTPdata(1, this.inputStream);
bytesRead = outPak.getLength();
outPak.send(this.ipAddress, this.port, this.socket);
for (int blkNum = 2; bytesRead == TFTPpacket.maxTftpPakLen; blkNum++) {
TFTPpacket ack = TFTPpacket.receive(this.socket);
if ((ack instanceof TFTPerror))
break;
TFTPack tack = (TFTPack) ack;
int ackNumber = tack.blockNumber();
System.out.println("service ackNumber: " + ackNumber);
if (ackNumber == blkNum - 1) {
outPak = new TFTPdata(blkNum, this.inputStream);
bytesRead = outPak.getLength();
outPak.send(this.ipAddress, this.port, this.socket);
} else {
outPak.send(this.ipAddress, ack.getPort(), this.socket);
blkNum--;
}
}
} catch (NullPointerException e) {
errorMessage("service TFTPread: File not Found");
try {
this.inputStream.close();
this.socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (Exception e) {
errorMessage(e);
try {
this.inputStream.close();
this.socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} finally {
try {
this.inputStream.close();
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
this.inputStream.close();
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
} else if ((this.request instanceof TFTPwrite)) {
System.out.println("write request service method");
TFTPdata p = null;
TFTPpacket inPak = null;
TFTPack ack = null;
int count = 0;
int loop = 3;
try {
ack = new TFTPack(0);
ack.send(this.ipAddress, this.port, this.socket);
int pakCount = 0;//这里需要从0开始,不是1,不然会少一帧4位
for (int bytesOut = 512; bytesOut == 512; pakCount++) {
if ((inPak instanceof TFTPerror)) {
return;
}
if ((inPak instanceof TFTPdata)) {
p = (TFTPdata) inPak;
int blockNum = p.blockNumber();
if (blockNum == pakCount) {
count = 0;
bytesOut = p.write(this.outputStream);
ack = new TFTPack(blockNum);
} else {
if (count == 3) {
return;
}
count++;
pakCount--;
ack = new TFTPack(pakCount);
}
// System.out.println("write: bytesOut: " + bytesOut + " count:" + count);
ack.send(p.getAddress(), p.getPort(), this.socket);
}
loop = 3;
while (loop > 0) {
loop--;
try {
inPak = TFTPpacket.receive(this.socket);//超时处理
loop = -1;
} catch (Exception e) {
ack.send(p.getAddress(), p.getPort(), this.socket);
}
}
}
} catch (Exception e) {
errorMessage(e);
}
}
}
public void start() {
Thread serviceExecutor = new Thread(this);
serviceExecutor.start();
}
public void errorMessage(String mesage) {
TFTPerror ePak = new TFTPerror(1, mesage);
try {
ePak.send(this.ipAddress, this.port, this.socket);
} catch (Exception localException) {
System.out.println("errorMessage: " + localException);
}
}
public void errorMessage(Exception e) {
e.printStackTrace();
TFTPerror ePak = new TFTPerror(1, e.getMessage());
try {
ePak.send(this.ipAddress, this.port, this.socket);
} catch (Exception localException) {
}
}
public void stop() {
this.socket.close();
}
}
TftpServer.java:(启动服务端)
import xxx.TFTPpacket;
import xxx.TFTPread;
import xxx.TFTPwrite;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* TFTP Server start
*
* @author: zhangyongtao
* @date: 2022/7/10
*/
public class TftpServer implements Runnable {
private static final String TAG = "TftpServer";
private DatagramSocket socket;
private int port = 69;
private final String tftpRoot;
public TftpServer(String tftpRootPath, int port) {
this.tftpRoot = tftpRootPath;
this.port = port;
}
public void start() {
Thread serviceExecutor = new Thread(this);
serviceExecutor.start();
}
public void stop() {
this.socket.close();
}
@Override
public void run() {
initilize();
service();
}
public void initilize() {
try {
this.socket = new DatagramSocket(this.port, InetAddress.getByName("192.168.xx.xx"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void service() {
try {
while (true) {
TFTPpacket in = TFTPpacket.receive(this.socket);
if (in != null) {
if ((in instanceof TFTPread)) {
System.out.println("Read request is received");
TFTPServiceHandler handler = new TFTPServiceHandler((TFTPread) in, this.tftpRoot);
handler.start();
}
if ((in instanceof TFTPwrite)) {
System.out.println("Write request is received");
TFTPServiceHandler handler = new TFTPServiceHandler((TFTPwrite) in, this.tftpRoot);
handler.start();
continue;
}
} else {
System.out.println("null request");
}
}
} catch (Exception localException) {
}
}
public static void main(String[] args) {
String path = "D:\\Program Files\\Tftpd64";//随意设置服务端目录
int port = 169;//这里端口号设为了169,一般为69
new TftpServer(path, port).start();
System.out.println("TFTp Server listening in the port " + port + " \n tftp root path:" + path);
}
}
以上就是服务端的编写,接下来是客户端Client的编写(主要是文件上传下载功能):
TFTPClient.java:
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
* TFTP Client
*
* @author: zhangyongtao
* @date: 2022/7/13
*/
public class TFTPClient {
private static final String TFTP_SERVER_ADDRESS = "192.168.xx.xx";
private static final String TFTP_MODE = "octet";
private static final int TFTP_SERVER_PORT = 169;
private static final byte OP_RRQ = 1;
private static final byte OP_WRQ = 2;
private static final byte OP_DATA_PACKET = 3;
private static final byte OP_ACK = 4;
private static final byte OP_ERROR = 5;
private static final int PACKET_SIZE = 516;
private DatagramSocket datagramSocket;
private InetAddress inetAddress;
private byte[] requestByteArray;
private byte[] bufferByteArray;
private DatagramPacket inDatagramPacket;
private DatagramPacket outDatagramPacket;
/**
* 从TFTP服务器上获取文件
*
* @param fileName 要获取的文件名字
* @param writeToLocalPath 要写入的本地路径
* @throws IOException 异常
*/
private void get(final String fileName, final String writeToLocalPath) throws IOException {
//准备IP
inetAddress = InetAddress.getByName(TFTP_SERVER_ADDRESS);
datagramSocket = new DatagramSocket();
//创建下载请求数据包
requestByteArray = createRequest(OP_RRQ, fileName, TFTP_MODE);
//配置目标发送包
outDatagramPacket = new DatagramPacket(requestByteArray, requestByteArray.length,
inetAddress, TFTP_SERVER_PORT);
//发送请求数据包RRQ
datagramSocket.send(outDatagramPacket);
//从TFTP服务端接收文件
ByteArrayOutputStream byteArrayOutputStream = receiveFile();
//向本地写入文件
writeFile(byteArrayOutputStream, writeToLocalPath);
}
/*
* 客户端向 TFTP 服务器发送写入请求(WRQ)。
* 1、服务器收到客户端的 WRQ 请求后,同意该请求,返回 ACK 确认包。这里的确认包的数据编号为 0。
* 2、客户端收到请求的确认包以后,得知服务器已经同意文件上传。客户端开始进行文件上传,向服务器发送文件信息数据。
* 首先发送第 1 个 DATA 包,大小为 512 字节,此时包的数据编号为 1,因为步骤(2)中已经使用了数据编号 0。
* 3、服务器收到客户端发来的数据编号为 1 的 DATA 包,并进行确认,向客户端发送数据编号为 1 的 ACK 包。
* 4、一直到文件没有字节可读取发送
* */
private static String LOCAL_CHARSET = "GBK";
// FTP协议里面,规定文件名编码为iso-8859-1
private static String SERVER_CHARSET = "ISO-8859-1";
private void put(final String fileName, final String localFilePath) throws IOException {
//准备IP
inetAddress = InetAddress.getByName(TFTP_SERVER_ADDRESS);
datagramSocket = new DatagramSocket();
// String fileNameContent = new String(fileName.getBytes("GBK"), "iso-8859-1");
// new String(userName.getBytes("ISO-8859-1"), "UTF-8");
// String fileNameContent = new String(fileName.getBytes(StandardCharsets.ISO_8859_1), "UTF-8");
// String localFilePathContent = new String(localFilePath.getBytes("GBK"), "iso-8859-1");
// System.out.println("" + fileNameContent + " - " + "localFilePathContent");
//创建上传请求数据包
requestByteArray = createRequest(OP_WRQ, fileName, TFTP_MODE);
//配置目标发送包
outDatagramPacket = new DatagramPacket(requestByteArray, requestByteArray.length,
inetAddress, TFTP_SERVER_PORT);
//发送请求数据包WRQ
datagramSocket.send(outDatagramPacket);
sendFile(localFilePath);
}
/*
* TFTP data packet format TFTP error packet
* 2bytes 2bytes max512bytes 2bytes 2bytes string 1byte
* OPCODE BLOCK# DATA OPCODE ERRCODE ERR_message 0
* */
private void sendFile(String localFilePath) throws IOException {
System.out.println("send File...");
File file = new File(localFilePath);
InputStream inputStream = new FileInputStream(file);
System.out.println("send File length: " + file.length());
DataInputStream dataInputStream = new DataInputStream(inputStream);
int blockNum = 1;
System.out.println("blockNum: " + blockNum);
while (true) {
bufferByteArray = new byte[PACKET_SIZE];
inDatagramPacket = new DatagramPacket(bufferByteArray, bufferByteArray.length,
inetAddress, datagramSocket.getLocalPort());
//从TFTP服务端接收数据包packet,接收到ACK码
datagramSocket.receive(inDatagramPacket);
//获取packet前4位数据OPCODE
byte[] opCode = {bufferByteArray[0], bufferByteArray[1]};
System.out.println("TFTP Packet bufferByteArray: " + bufferByteArray[0] +
", " + bufferByteArray[1]);
// System.out.println("BufferByteArray: " + Arrays.toString(bufferByteArray));
// System.out.println("AAAAAAA OP_CODE: " + opCode[1]);
if (opCode[1] == OP_ERROR) {
System.out.println("TFTP OP_Error");
outputError();
} else if (opCode[1] == OP_ACK) {
System.out.println("TFTP OP_ACK");
DatagramPacket datagramPacket;
System.out.println("dataInputStream short: " + dataInputStream.available());
bufferByteArray[0] = 0;
bufferByteArray[1] = 3;
bufferByteArray[2] = 0;
put(2, (short) blockNum, bufferByteArray);
dataInputStream.read(bufferByteArray, 4, bufferByteArray.length - 4);
datagramPacket = new DatagramPacket(bufferByteArray, bufferByteArray.length,
inDatagramPacket.getAddress(), inDatagramPacket.getPort());
System.out.println("blockNumber: " + bufferByteArray[2] + bufferByteArray[3]);
// System.out.println("TFTP OP_ACK: " + Arrays.toString(bufferByteArray) + " length: " + bufferByteArray.length);
// System.out.println("length: " + datagramPacket.getLength());
datagramSocket.send(datagramPacket);
//当流里面没有字节可读时退出
if (dataInputStream.available() <= 0) {
System.out.println("dataInputStream.available() <= 0");
return;
}
blockNum++;
}
}
}
/*
* RRQ、WRQ请求数据包格式:
* 2bytes | string | 1byte | string | 1byte|
* OPCODE | FileName | 0 | mode | 0 |
* */
private byte[] createRequest(final byte opcode, final String fileName, final String mode) {
byte zeroByte = 0;
//请求数据包长度
int rrqByteLength = 2 + fileName.length() + 1 + mode.length() + 1;
byte[] rrqByteArray = new byte[rrqByteLength];
//开始填充
int position = 0;
rrqByteArray[position] = zeroByte;
position++;
rrqByteArray[position] = opcode;
position++;
for (int i = 0; i < fileName.length(); i++) {
rrqByteArray[position] = (byte) fileName.charAt(i);
position++;
}
rrqByteArray[position] = zeroByte;
position++;
for (int i = 0; i < mode.length(); i++) {
rrqByteArray[position] = (byte) mode.charAt(i);
position++;
}
rrqByteArray[position] = zeroByte;
return rrqByteArray;
}
//写入本地
private void writeFile(ByteArrayOutputStream byteArrayOutputStream, String writeToLocalPath) {
try {
OutputStream outputStream = new FileOutputStream(writeToLocalPath);
System.out.println("TFTP Client write File path: " + writeToLocalPath);
byteArrayOutputStream.writeTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* TFTP data packet format TFTP error packet
* 2bytes 2bytes max512bytes 2bytes 2bytes string 1byte
* OPCODE BLOCK# DATA OPCODE ERRCODE ERR_message 0
* */
private ByteArrayOutputStream receiveFile() throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int block = 1;
do {
System.out.println("TFTP Packet block: " + block);
block++;
bufferByteArray = new byte[PACKET_SIZE];
inDatagramPacket = new DatagramPacket(bufferByteArray, bufferByteArray.length,
inetAddress, datagramSocket.getLocalPort());
System.out.println("TFTP Packet count2: bufferByteArray length:" + bufferByteArray.length
+ " inetAddress: " + inetAddress + " current port: " + datagramSocket.getLocalPort());
//从TFTP服务端接收数据包packet
datagramSocket.receive(inDatagramPacket);
//获取packet前4位数据OPCODE
byte[] opCode = {bufferByteArray[0], bufferByteArray[1]};
System.out.println("TFTP Packet bufferByteArray: " + bufferByteArray[0] +
", " + bufferByteArray[1]);
if (opCode[1] == OP_ERROR) {
System.out.println("TFTP OP_Error");
outputError();
} else if (opCode[1] == OP_DATA_PACKET) {
System.out.println("TFTP Client received Data Packet");
byte[] blockNumber = {bufferByteArray[2], bufferByteArray[3]};
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.write(inDatagramPacket.getData(), 4,
inDatagramPacket.getLength() - 4);
InetAddress address = inDatagramPacket.getAddress();
int port = inDatagramPacket.getPort();
SocketAddress socketAddress = inDatagramPacket.getSocketAddress();
int length = inDatagramPacket.getLength();
byte[] data = inDatagramPacket.getData();
System.out.println("TFTP receive address: " + address + " port: " + port +
" socketAddress: " + socketAddress + " length: " + length + " data: " +
Arrays.toString(data));
//向TFTP服务端发送确认码ACK,通知写入
sendAcknowledgement(blockNumber);
}
} while (!isLastPacket(inDatagramPacket));
return byteArrayOutputStream;
}
/*
* 发送ACK确认码
* ACK Packet: 2bytes:OPCODE 2bytes:Block number
* */
private void sendAcknowledgement(byte[] blockNumber) {
byte[] ACK = {0, OP_ACK, blockNumber[0], blockNumber[1]};
DatagramPacket datagramPacket = new DatagramPacket(ACK, ACK.length,
inetAddress, inDatagramPacket.getPort());
System.out.println("sendAcknowledgement: " + Arrays.toString(ACK));
try {
datagramSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
//是否最后一个包
private boolean isLastPacket(DatagramPacket inDatagramPacket) {
return inDatagramPacket.getLength() < 512;
}
//输出错误信息
private void outputError() {
String code = new String(bufferByteArray, 3, 1);
String errorText = new String(bufferByteArray, 4, inDatagramPacket.getLength() - 4);
System.out.println("TFTP Client Error code: " + code + " text: " + errorText);
}
protected void put(int at, short value, byte[] bufferByteArray) {
int atLocal = at;
bufferByteArray[(atLocal++)] = (byte) (value >>> 8);
//383 0001 1000 0000 256 127 0000 0001
bufferByteArray[atLocal] = (byte) (value & 0xff);//取余
}
public static void main(String[] args) throws UnknownHostException {
final String TFTP_SERVER_ADDRESS = "192.168.xx.xx";
final String TFTP_MODE = "octet";
final int TFTP_SERVER_PORT = 169;
InetAddress inetAddress = InetAddress.getByName(TFTP_SERVER_ADDRESS);
TFTPClient tftpClient = new TFTPClient();
try {
tftpClient.put("tiger.png", "F:\\老虎.png");
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端编写结束,以上,结束。代码有借鉴别人的(不全,全是片段和原理)…