0

1)问题:两个while循环是否同时运行?我想知道的是 main() 方法中的 while 循环正在运行,而 sendDATA 中的 while 循环正在执行?

2)如果不是我怎么能同时发送和接收。我必须实现 TFTP,所以我必须读取并发送每个数据包 512 个字节,所以:我读取 512 个字节并发送它们,然后等待 ACK 数据包从客户端到达 ACK Packet = |opcode|block#| 所以传入[0] = 3 和传入[1] = int 块#

如果传入的块编号与我发送的匹配,那么我可以发送下一个数据包,否则我必须发送前一个数据包。我不知道如何用一个循环来实现这一点。

我的代码:

package source;

import java.io.*;
import java.net.*;
import java.nio.*;
import java.util.Scanner;

public class Server
{


    static String[] errorcodes = {"Not defined", "File not found", "Access violation", "Disk full or allocation exceeded", "Illegal TFTP Operation",
                              "Unknown transfer ID", "File already exists", "No such user"}; 

    static String FILE = "";
    static String MODE = "";

    static byte[] outgoing = new byte[512];
    static byte[] incoming = new byte[512];

    static DatagramSocket socket;

    static String clientip;
    static int clientport;


    public static void main(String[] args) throws Exception
    {   
        socket = new DatagramSocket(13373); // 69 Reserved for TFTP

        // Listen for incoming packets
        while(true) {
            DatagramPacket packet = new DatagramPacket(incoming, incoming.length);
            socket.receive(packet);

            clientip = packet.getAddress().toString().replace("/", "");
            clientport = packet.getPort();

            System.out.println(clientport);

            if(incoming[0] == 1 || incoming[0] == 2) {
                handleRequest(incoming);
            }

        }
    }

    // sends DATA opcode = 3 : | opcode | block # | data |
    private static void sendDATA() {
        outgoing = new byte[512]; // Empty array
        try {
            ByteBuffer sDATA = ByteBuffer.allocate(516);
            // 512 - 2 byte opcode, 2 byte block #, 512 data

            DatagramPacket data = new DatagramPacket(outgoing, outgoing.length, InetAddress.getByName(clientip), clientport);
            InputStream fis = new FileInputStream(new File(FILE));

            int a;
            int block = 1;



            while((a = fis.read(outgoing,0,512)) != -1)
            {
                data.setLength(a);
                sDATA.put((byte)3);
                sDATA.put((byte)block);
                sDATA.put(outgoing);
                socket.send(data);

                if(incoming[0] == 3 && incoming[1] == block) 
                {

                }

            }


        } catch (Exception e) {

        }

    }


    // Request packet: | opcode | filename | 0 | mode | 0 |
    // Upravlja le z WRQ / RRQ opcode
    private static void handleRequest(byte[] packet) 
    {

        int opcode = packet[0];
        String filename = "";
        int offset = 0;
        String mode = "";

        // Get filename
        for(int i = 1; i < packet.length; i++) {
            if(packet[i] != 0) {
                filename += (char)packet[i];
            } else {
                offset = i;
                break;
            }
        }
        // Get mode
        for(int j =  offset; j < packet.length; j++) {
            if(packet[j] != 0) {
                mode += (char)packet[j];
            }
        }
        FILE = filename;
        MODE = mode;
        if(opcode == 1) {
            // Do RRQ
            File test = new File(filename);
            if(test.exists()) {
                sendACK(); 
            } else {
                sendERROR(1);
            }
        } else {
            // Do WRQ
            File test2 = new File(filename);
            if(test2.exists()) {
                sendERROR(6);
            } else {
                sendACK();
            }
        }
    }


    // send ACK opcode = 4 : | opcode | block # |
    // block 0 -> prvi ACK, odgovor na RRQ/WRQ 
    // block 1 -> stevilo poslanega bloka, stetje blokov se zacne
    // pri 1.
    private static void sendACK() {
        outgoing = new byte[512];
        outgoing[0] = (byte)4;
        outgoing[1] = (byte)0;

        try {
            DatagramPacket ackpacket = new DatagramPacket(outgoing, outgoing.length, InetAddress.getByName(clientip), clientport);
            socket.send(ackpacket);
        } catch(Exception e) {

        }
    }   

    // send ERROR packet opcode =  5 : | opcode | errorcode | msg | 0 |
    // General errorcodes: 2
    private static void sendERROR(int errorcode) {
        ByteBuffer errpack = ByteBuffer.allocate(512);
        errpack.put((byte)5); // opcode
        errpack.put((byte)errorcode); // errorcode
        try {
            errpack.put(errorcodes[errorcode].getBytes("US-ASCII")); // msg
            errpack.put((byte)0);

            outgoing = errpack.array(); // Pack ERROR Packet

            DatagramPacket errpacket = new DatagramPacket(outgoing, outgoing.length, InetAddress.getByName(clientip), clientport);
            socket.send(errpacket);

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

}
4

1 回答 1

0

问题:两个while循环是否同时运行?我想知道的是 main() 方法中的 while 循环正在运行,而 sendDATA 中的 while 循环正在执行?

不会。但是当您调用 handleRequest 时,传入的 UDP 数据包会被缓冲(达到一定限制)。这样当handleRequest 返回时,如果有新的UDP 数据包可用,随后对socket.receive() 的调用将立即返回。如果您在“handleRequest”调用中花费的时间过长,这并不能保证您不会丢失数据包。但它可能适用于合理的负载和小文件。

如果不是,我怎么能同时发送和接收。

您应该保留一个数据结构来保存每个会话的状态。(例如,正在传输什么文件,到目前为止传输了多少字节,确认状态等...)将每个会话存储在某个集合/列表中。这样您的代码逻辑看起来像这样:

// this is not java, just pseudo code
while (true)
{
    packet = receive packet from network
    session = list_of_sessions.lookup(packet.fromaddress)
    if (session == null)
    {
        session = new Session(packet)
        list_of_sessions.add(new Session(), packet.fromaddress)
    }
    handleRequest(packet, session); // sends a response based on state or packet received
    if (session.isFinished)
    {
        list_of_sessions.remove(session)    
    }
}

上面的单线程方法可能最适合您。但如果你想变得狂野,你可以投资线程。我不确定你是否准备好了。

于 2012-09-12T15:29:41.220 回答