如何设置java UDP数据报数据包的前2个字节?

如何设置java UDP数据报数据包的前2个字节?,java,udp,datagram,Java,Udp,Datagram,我有一个客户端服务器程序试图发送一个jpg文件 我试图向UDP数据包添加一个确认字节和数据的BlockNumber字节。我在这部分代码中遇到了问题(这部分代码只是来自客户端程序的数据块处理代码): 上面的代码不适用于我的服务器,服务器是由老师制作的。我已经检查了服务器代码,看起来很棒 出于某种原因,它挂在应该发送包含整数的确认字节的部分,“3”表示“已确认”。它应该在buff.array()的零位置包含ACK字节。但是服务器说没有收到确认字节 TftpUtil的开头是这样的: public cl

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

我试图向UDP数据包添加一个确认字节和数据的BlockNumber字节。我在这部分代码中遇到了问题(这部分代码只是来自客户端程序的数据块处理代码):

上面的代码不适用于我的服务器,服务器是由老师制作的。我已经检查了服务器代码,看起来很棒

出于某种原因,它挂在应该发送包含整数的确认字节的部分,“3”表示“已确认”。它应该在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;  
}
服务器所做的是发送一个.jpg文件,数据块为512字节。服务器检测到已建立连接,并尝试发送文件。它发送第一个数据块,这似乎通过了,因为当我检查文件夹时,有一个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,0,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;
    }
}
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.net.DatagramPacket;
导入java.net.DatagramSocket;
导入java.net.InetAddress;
导入java.net.SocketAddress;
导入java.net.SocketTimeoutException;
导入java.nio.ByteBuffer;
导入java.util.concurrent.Executors;
导入java.util.concurrent.ExecutorService;
公共类服务器\u v004{
私有地址服务器地址;
专用int服务器端口;
私有DatagramSocket服务器套接字;
private static final ExecutorService exec=Executors.newFixedThreadPool(10);
public void startServer()
{
试一试{
字符串serverIpAddress=“192.168.1.32”;
InetAddress echoServerIP=InetAddress.getByName(服务器IP地址);
serverSocket=新的DatagramSocket(serverPort,echoServerIP);
System.out.println(“端口上的TftpServer”+serverSocket.getLocalPort());
while(true){
字节[]buf=新字节[1472];
DatagramPacket p=新的DatagramPacket(buf,1472);
System.out.println(“等待连接…”);
serverSocket.receive(p);
服务器\u v004ServerWorker=新服务器\u v004ServerWorker(p);
执行(工人);
}
}
捕获(例外e){
System.err.println(“异常:+e”);
}
serverSocket.close();
返回;
}
公共静态void main(字符串[]args){
服务器_v004 tftpServer=新服务器_v004();
//tftpServer.checkArgs(args);
试一试{
tftpServer.parseArgsAndInit(args);
tftpServer.startServer();
}
捕获(例外e){
e、 printStackTrace();
}
}
私有void checkArgs(字符串[]args){

如果(args.length我们可能会使用该服务器代码,只是为了查看实际需要的代码。我们还可以使用生成的错误消息。要调试此代码,请在您自己的计算机上同时设置客户端和服务器,以便您可以查看两端的操作。您需要同时查看这两个代码,或者您只是猜测实际问题是什么。我可以同时看到d一定要在本地运行它。我打算使用wireshark,这有用吗?如果它在本地工作,你应该和你的老师谈谈。问题可能在他或她这方面。你能找到服务器可能会采取的错误路径吗?服务器可能会产生什么错误消息?你在哪里可以找到这些错误?哦,说到本地与远程:这是我的问题s UDP。您确定数据包正在到达服务器吗?如果这些数据包有可能被丢弃,在服务器端运行Wireshark可能是个好主意。它们都位于相同的IP地址上,在套接字69(服务器)和另一个随机套接字(客户端)之间跳转数据包。
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,0,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,1, 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
       
   }
    
}