问题描述
我正在尝试向UDP数据包添加一个ACKNowLEDGE字节和DATA的BlockNumber字节。我在代码的这一部分遇到了麻烦(代码的这一部分只是来自Client程序的DATA Block处理代码):
if(pType == Tftputil.DATA){ //If byte 0 = 2 meaning it's a DATA block.
private int blockNumber = 1;
byte[] bn = intToBytes(blockNumber);
ByteBuffer buff = ByteBuffer.allocate(8); // For 2 ints,an int is 4 bytes long
buff.put(Tftputil.ACK); // This is an "ACKNowLEDGE byte",at position zero.
buff.put(bn); // This is supposed to be a byte containing the integer "blockNumber" meaning,what DATA block in the series it is.
buff.rewind(); // Not sure what this does. What does this do? Saw it in the code I copied.
DatagramPacket dataPacket = new DatagramPacket(buff.array(),buff.limit(),echoServerIP,69); //Create datagramPacket
System.out.println("TftpClient sending a ACK on port " + clientSocket.getLocalPort());
clientSocket.send(dataPacket);
blockNumber++;
}
上面的代码不适用于我拥有的服务器,并且该服务器是由教师制作的。我已经检查了服务器代码,看起来不错。
由于某种原因,它挂在应该发送包含整数“ 3”(表示“已确认”)的ACKNowLEDGE字节的部分。并且应该在buff.array()的零位置包含该ACK字节。但是服务器说没有收到确认字节。
Tftputil像这样开始:
public class Tftputil {
//read request packet
public static final byte RRQ = 1;
//data packet
public static final byte DATA = 2;
//ack packet
public static final byte ACK = 3;
//error packet
public static final byte ERROR = 4;
//the maximum number of resent
public static final int MAX_RESEND = 5;
//data buffer size: 512
public static int DATA_BUFFER_SIZE = 512;
//packet buffer size: 2 bytes header + 512 bytes file data;
public static int PACKET_BUFFER_SIZE = DATA_BUFFER_SIZE + 2;
}
服务器正在执行的操作是以512字节的DATA块发送一个.jpg文件。服务器发现已建立连接,并尝试发送文件。它发送第一个DATA块,因为我检查文件夹时似乎通过了一个512字节的asd.jpg文件。但是,当客户端发送回ACK字节时,服务器会说这是不正确的,并且超时。
谢谢。
更新完整的服务器代码:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.socketAddress;
import java.net.socketTimeoutException;
import java.nio.ByteBuffer;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class server_v004 {
private InetAddress serverAddress;
private int serverPort;
private DatagramSocket serverSocket;
private static final ExecutorService exec = Executors.newFixedThreadPool(10);
public void startServer()
{
try {
String serverIpAddress = "192.168.1.32";
InetAddress echoServerIP = InetAddress.getByName(serverIpAddress);
serverSocket = new DatagramSocket(serverPort,echoServerIP);
System.out.println("TftpServer on port " + serverSocket.getLocalPort());
while(true) {
byte[] buf = new byte[1472];
DatagramPacket p = new DatagramPacket(buf,1472);
System.out.println("waiting for connection ....");
serverSocket.receive(p);
server_v004ServerWorker worker = new server_v004ServerWorker(p);
exec.execute(worker);
}
}
catch(Exception e) {
System.err.println("Exception: " + e);
}
serverSocket.close();
return;
}
public static void main(String[] args) {
server_v004 tftpServer = new server_v004();
//tftpServer.checkArgs(args);
try{
tftpServer.parseArgsAndInit(args);
tftpServer.startServer();
}
catch(Exception e){
e.printstacktrace();
}
}
private void checkArgs(String[] args){
if(args.length <0) { //<1 //<2
System.out.println("Usage: TftpServer"); //server_port server_ip
System.exit(0);
}
}
private void parseArgsAndInit(String[] args) throws Exception{
//serverAddress = InetAddress.getByName(args[0]);
serverPort = 12345; //Integer.parseInt(args[1]);
}
}
class server_v004ServerWorker implements Runnable
{
//use to store RRQ request
private DatagramPacket req;
//client address who sent the RRQ request
private SocketAddress clientAddress;
//socket used to send the file data packets to client
private DatagramSocket sendfileSocket;
//byte buffer to store the file data
private byte[] dataBuffer = new byte[Tftputil.DATA_BUFFER_SIZE];
//the first block sequence
private byte currentBlockSeq = 1;
//use to retrieve the ack packet,only two bytes long
private DatagramPacket ackDP = new DatagramPacket(new byte[2],2);
private int TIME_OUT = 1000; //1 second
public void run(){
try{
sendfileSocket = new DatagramSocket(69);
System.out.println("TftpServer sending a file on port " + sendfileSocket.getLocalPort());
byte pType = Tftputil.checkPacketType(req);
clientAddress = req.getSocketAddress();
//checking if the first packet from client is a RRQ packet
if(pType == Tftputil.RRQ){
String filename = getFileName(req);
System.out.println("Requested file name:" + filename);
//if the file doesn't exist,send ERROR packet and close socket
if(!(new File(filename)).exists()) {
DatagramPacket errorDP = Tftputil.packerrorPacket(filename);
errorDP.setSocketAddress(clientAddress);
sendfileSocket.send(errorDP);
}
else{
//the file does exist,send file
sendfile(filename);
}
}// end if
}catch(Exception e){
e.printstacktrace();
}
sendfileSocket.close();
return;
}
private void sendfile(String filename) throws Exception{
FileInputStream fileInput = new FileInputStream(filename);
while(true){
int rec = fileInput.read(dataBuffer);
//the file size is a multiple of 512,send empty packet
if(rec == -1){
sendDataPacket(new byte[0],0);
System.out.println("The last packet [0 byte in size]:#"+currentBlockSeq);
break;
}
//send a file data packet
boolean successed = sendDataPacket(dataBuffer,rec);
//tried five times
if (!successed) {
System.out.println("Tried five times,give up");
System.exit(0);
}
// the last packet (the file size if not a multiple of 512)
if (rec < 512 && rec > 0 ) {
System.out.println("The last packet ["+rec+" bytes in size]:#"+currentBlockSeq);
break;
}
currentBlockSeq++;
}//while
fileInput.close();
}
//
private boolean sendDataPacket(byte[] databuffer,int length) throws Exception{
int resendCount = 0;
DatagramPacket dataPacket = packFileDataPacket(databuffer,length);
//try five times
while(resendCount < Tftputil.MAX_RESEND){
try{
sendfileSocket.send(dataPacket);
sendfileSocket.setSoTimeout(TIME_OUT);
System.out.println("sent data block #"+currentBlockSeq+",waiting for ack #" + currentBlockSeq);
//ack arrives
sendfileSocket.receive(ackDP);
byte ackedBlockseq = Tftputil.extractACKNumber(ackDP);
System.out.println("received ack #" + ackedBlockseq);
if(ackedBlockseq != currentBlockSeq) {
//the acked block seq is not the seq of block sent
//ignore this ack and resend
resendCount++;
continue;
}
//this data packet has been acked,return
return true;
}//end of try
catch(SocketTimeoutException ste){
resendCount++;
System.out.println("timeout #" + resendCount );
}
}//end of while
return false;
}
private DatagramPacket packFileDataPacket(byte[] dataBuffer,int length){
int packetLength = 2 + length;//type (1) + block seq (1) + data length
ByteBuffer byteBuffer = ByteBuffer.allocate(packetLength);
byteBuffer.put(Tftputil.DATA);//type
byteBuffer.put(currentBlockSeq);//block seq
byteBuffer.put(dataBuffer,length);//data
DatagramPacket dataPacket = new DatagramPacket(byteBuffer.array(),packetLength);
dataPacket.setSocketAddress(clientAddress);
return dataPacket;
}
private String getFileName(DatagramPacket dataDP){
byte[] data = dataDP.getData();
int dataLength = dataDP.getLength();
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength-1);
//remove the packet type (RRQ)
byteBuffer.put(data,1,dataLength-1);
return new String(byteBuffer.array());
}
public server_v004ServerWorker(DatagramPacket req)
{
this.req = req;
}
}
import java.net.DatagramPacket;
import java.nio.ByteBuffer;
public class Tftputil {
//read request packet
public static final byte RRQ = 1;
//data packet
public static final byte DATA = 2;
//ack packet
public static final byte ACK = 3;
//error packet
public static final byte ERROR = 4;
//the maximum number of resent
public static final int MAX_RESEND = 5;
//data buffer size: 512
public static int DATA_BUFFER_SIZE = 512;
//packet buffer size: 2 bytes header + 512 bytes file data;
public static int PACKET_BUFFER_SIZE = DATA_BUFFER_SIZE + 2;
//return the type (RRQ,DATA,ACK or ERROR) of a packet
public static byte checkPacketType(DatagramPacket dataDP){
byte[] payload = dataDP.getData();
return payload[0];
}
//return a RRQ packet
public static DatagramPacket packRRQDatagramPacket(byte[] filename) throws Exception{
return packDatagramPacket(RRQ,filename);
}
//return a "file not found" error packet
public static DatagramPacket packerrorPacket(String filename) throws Exception{
String errorMessage = filename + " not found";
return packDatagramPacket(ERROR,errorMessage.getBytes());
}
/*
* utility method that wrap a packet type,data into a DatagramPacket
*/
private static DatagramPacket packDatagramPacket(byte type,byte[] payload) throws Exception{
int dataLength = 1 + payload.length;
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength);
byteBuffer.put(type);
byteBuffer.put(payload);
return new DatagramPacket(byteBuffer.array(),dataLength);
}
//return the ack number of a ACK packet
public static byte extractACKNumber(DatagramPacket ackDP){
byte[] payload = ackDP.getData();
return payload[1];
}
//print the string content of a ERROR packet
public static void printErrorString(DatagramPacket p){
byte[] data = p.getData();
int dataLength = p.getLength();
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength-1);
//ignore the packet type
byteBuffer.put(data,dataLength-1);
System.out.print(new String(byteBuffer.array()));
}
//return the block sequence of a data packet
public static byte extractBlockSeq(DatagramPacket dataDP){
byte[] payload = dataDP.getData();
if(payload.length <=1) return -1; //-1: no block sequence in data
int type = payload[0];
if(type == DATA){
return payload[1];
}
return -1; //-1: not a data packet
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)