如何在Java UDP数据报包上设置前2个字节?

问题描述

我有一个客户端服务器程序试图发送jpg文件

我正在尝试向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;
    }
}

以及完整的Tftputil代码

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 (将#修改为@)