基于RFC1350,怎么写TFTP-UDP服务器和客户端。用Java
要编写TFTP-UDP服务器和客户端,您需要遵循RFC1350中定义的TFTP协议规范。TFTP是基于UDP协议的简单文件传输协议,其使用的端口号为69。在Java中,您可以使用Java Socket API来实现TFTP客户端和服务器。下面是一些步骤,可以帮助您开始编写TFTP-UDP服务器和客户端。
TFTP-UDP服务器:
import java.net.*;
import java.io.*;
public class TFTPServer {
private static final int SERVER_PORT = 69;
public static void main(String[] args) throws Exception {
//创建一个Java程序来接收来自TFTP客户端的UDP数据包。
DatagramSocket serverSocket = new DatagramSocket(SERVER_PORT);
System.out.println("TFTP server is running on port " + SERVER_PORT);
while (true) {
byte[] receiveData = new byte[516];
//建一个DatagramPacket对象来保存接收到的数据包。
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
new Thread(new TFTPServerThread(receivePacket)).start();
}
}
}
class TFTPServerThread implements Runnable {
private DatagramPacket receivePacket;
public TFTPServerThread(DatagramPacket receivePacket) {
this.receivePacket = receivePacket;
}
public void run() {
try {
DatagramSocket socket = new DatagramSocket();
InetAddress clientAddress = receivePacket.getAddress();
int clientPort = receivePacket.getPort();
byte[] data = receivePacket.getData();
if (data[1] == 1) { // RRQ (read request)
String fileName = new String(data, 2, receivePacket.getLength() - 3);
System.out.println("Received RRQ for file " + fileName);
File file = new File(fileName);
if (!file.exists()) {
byte[] errorData = {0, 5, 0, 1, 'F', 'i', 'l', 'e', ' ', 'n', 'o', 't', ' ', 'f', 'o', 'u', 'n', 'd', 0};
DatagramPacket errorPacket = new DatagramPacket(errorData, errorData.length, clientAddress, clientPort);
socket.send(errorPacket);
System.out.println("File not found error sent");
return;
}
FileInputStream fileInputStream = new FileInputStream(file);
byte[] fileData = new byte[(int)file.length()];
fileInputStream.read(fileData);
fileInputStream.close();
int blockNum = 1;
int offset = 0;
while (offset < fileData.length) {
byte[] sendData = new byte[516];
sendData[0] = 0;
sendData[1] = 3;
sendData[2] = (byte)(blockNum >> 8);
sendData[3] = (byte)blockNum;
int length = Math.min(fileData.length - offset, 512);
System.arraycopy(fileData, offset, sendData, 4, length);
DatagramPacket sendPacket = new DatagramPacket(sendData, length + 4, clientAddress, clientPort);
socket.send(sendPacket);
byte[] receiveData = new byte[516];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
if (receiveData[1] != 4 || receiveData[2] != sendData[2] || receiveData[3] != sendData[3]) {
System.out.println("ACK mismatch, expected block " + blockNum);
continue;
}
blockNum++;
offset += length;
}
System.out.println("File transfer completed");
} else if (data[1] == 2) { // WRQ (write request)
String fileName = new String(data, 2, receivePacket.getLength() - 3);
System.out.println("Received WRQ for file " + fileName);
File file = new File(fileName);
if (file.exists()) {
byte[] errorData = {0, 5, 0, 6, 'F', 'i', 'l', 'e', ' ', 'a', 'l', 'r', 'e', 'a', 'd', 'y', ' ', 'e', 'x', 'i', 's', 't', 's', 0};
DatagramPacket errorPacket = new DatagramPacket(errorData, errorData.length, clientAddress, clientPort);
socket.send(errorPacket);
System.out.println("File already exists error sent");
return;
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
int blockNum = 0;
byte[] sendData = new byte[4];
sendData[0] = 0;
sendData[1] = 4;
sendData[2] = 0;
sendData[3] = 0;
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientAddress, clientPort);
socket.send(sendPacket);
while (true) {
byte[] receiveData = new byte[516];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
if (receiveData[1] != 3 || receiveData[2] != (byte)(blockNum >> 8) || receiveData[3] != (byte)blockNum) {
byte[] errorData = {0, 5, 0, 4, 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 'b', 'l', 'o', 'c', 'k', ' ', 'n', 'u', 'm', 'b', 'e', 'r', 0};
DatagramPacket errorPacket = new DatagramPacket(errorData, errorData.length, clientAddress, clientPort);
socket.send(errorPacket);
System.out.println("Invalid block number error sent, expected block " + blockNum);
continue;
}
int length = receivePacket.getLength() - 4;
fileOutputStream.write(receiveData, 4, length);
sendData[2] = (byte)(blockNum >> 8);
sendData[3] = (byte)blockNum;
sendPacket.setData(sendData);
sendPacket.setLength(sendData.length);
socket.send(sendPacket);
if (length < 512) {
break;
}
blockNum++;
}
fileOutputStream.close();
System.out.println("File transfer completed");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
TFTP-UDP客户端:
```java
import java.net.*;
import java.io.*;
public class TFTPClient {
private static final int SERVER_PORT = 69;
public static void main(String[] args) throws Exception {
if (args.length != 3) {
System.out.println("Usage: java TFTPClient <server> <get/put> <file>");
return;
}
String serverAddress = args[0];
String operation = args[1];
String fileName = args[2];
DatagramSocket socket = new DatagramSocket();
InetAddress serverInetAddress = InetAddress.getByName(serverAddress);
//byte[] data = new byte[516];
//data[0] = 0;
if ("put".equals(operation)) {
FileInputStream fileInputStream = new FileInputStream(fileName);
int blockNum = 0;
byte[] sendData = new byte[516];
sendData[0] = 0;
sendData[1] = 2;
byte[] fileNameBytes = fileName.getBytes();
System.arraycopy(fileNameBytes, 0, sendData, 2, fileNameBytes.length);
sendData[fileNameBytes.length + 2] = 0;
byte[] modeBytes = "octet".getBytes();
System.arraycopy(modeBytes, 0, sendData, fileNameBytes.length + 3, modeBytes.length);
sendData[fileNameBytes.length + modeBytes.length + 3] = 0;
DatagramPacket sendPacket = new DatagramPacket(sendData, fileNameBytes.length + modeBytes.length + 4, serverInetAddress, SERVER_PORT);
socket.send(sendPacket);
while (true) {
byte[] receiveData = new byte[516];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
if (receiveData[1] != 4 || receiveData[2] != (byte)(blockNum >> 8) || receiveData[3] != (byte)blockNum) {
throw new Exception("Invalid ACK received, expected ACK for block " + blockNum);
}
if (fileInputStream.available() > 0) {
int length = fileInputStream.read(sendData, 4, 512);
sendData[0] = 0;
sendData[1] = 3;
sendData[2] = (byte)(blockNum >> 8);
sendData[3] = (byte)blockNum;
sendPacket.setData(sendData);
sendPacket.setLength(length + 4);
socket.send(sendPacket);
blockNum++;
if (length < 512) {
break;
}
} else {
break;
}
}
fileInputStream.close();
System.out.println("File transfer completed");
} else if ("get".equals(operation)) {
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
int blockNum = 0;
byte[] sendData = new byte[516];
sendData[0] = 0;
sendData[1] = 1;
byte[] fileNameBytes = fileName.getBytes();
System.arraycopy(fileNameBytes, 0, sendData, 2, fileNameBytes.length);
sendData[fileNameBytes.length + 2] = 0;
byte[] modeBytes = "octet".getBytes();
System.arraycopy(modeBytes, 0, sendData, fileNameBytes.length + 3, modeBytes.length);
sendData[fileNameBytes.length + modeBytes.length + 3] = 0;
DatagramPacket sendPacket = new DatagramPacket(sendData, fileNameBytes.length + modeBytes.length + 4, serverInetAddress, SERVER_PORT);
socket.send(sendPacket);
while (true) {
byte[] receiveData = new byte[516];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
if (receiveData[1] != 3 || receiveData[2] != (byte)(blockNum >> 8) || receiveData[3] != (byte)blockNum) {
throw new Exception("Invalid data block received, expected block " + blockNum);
}
int length = receivePacket.getLength() - 4;
fileOutputStream.write(receiveData, 4, length);
byte[] ackData = {0, 4, (byte)(blockNum >> 8), (byte)blockNum};
DatagramPacket ackPacket = new DatagramPacket(ackData, ackData.length, serverInetAddress, receivePacket.getPort());
socket.send(ackPacket);
blockNum++;
if (length < 512) {
break;
}
}
fileOutputStream.close();
System.out.println("File transfer completed");
}
}
上述代码实现了一个基本的TFTP客户端。您可以通过将“get”或“put”作为第一个参数传递给该程序来指定要执行的操作。在“put”操作中,客户端将文件从本地计算机传输到TFTP服务器,而在“get”操作中,客户端从TFTP服务器获取文件并将其保存到本地计算机中。