{"id":329,"date":"2019-04-01T15:55:48","date_gmt":"2019-04-01T07:55:48","guid":{"rendered":"http:\/\/47.101.202.111\/?p=329"},"modified":"2023-04-21T08:57:22","modified_gmt":"2023-04-21T00:57:22","slug":"javatftp%e5%8d%8f%e8%ae%ae%e5%ae%9e%e7%8e%b0","status":"publish","type":"post","link":"http:\/\/139.196.114.170\/?p=329","title":{"rendered":"TFTP\u534f\u8bae\u5b9e\u73b0"},"content":{"rendered":"<h4>TFTP\u534f\u8bae\u7b80\u4ecb<\/h4>\n<p>TFTP\uff08Trivial File Transfer Protocol,\u7b80\u5355\u6587\u4ef6\u4f20\u8f93\u534f\u8bae\uff09\u662f TCP\/IP \u534f\u8bae\u65cf\u4e2d\u7684\u4e00\u4e2a\u7528\u6765\u5728\u5ba2\u6237\u673a\u4e0e\u670d\u52a1\u5668\u4e4b\u95f4\u8fdb\u884c\u7b80\u5355\u6587\u4ef6\u4f20\u8f93\u7684\u534f\u8bae\uff0c\u63d0\u4f9b\u4e0d\u590d\u6742\u3001\u5f00\u9500\u4e0d\u5927\u7684\u6587\u4ef6\u4f20\u8f93\u670d\u52a1\u3002TFTP \u627f\u8f7d\u5728 UDP \u4e0a\uff0c\u63d0\u4f9b\u4e0d\u53ef\u9760\u7684\u6570\u636e\u6d41\u4f20\u8f93\u670d\u52a1\uff0c\u4e0d\u63d0\u4f9b\u5b58\u53d6\u6388\u6743\u4e0e\u8ba4\u8bc1\u673a\u5236\uff0c\u4f7f\u7528\u8d85\u65f6\u91cd\u4f20\u65b9\u5f0f\u6765\u4fdd\u8bc1\u6570\u636e\u7684\u5230\u8fbe\uff0c\u4e0eFTP \u76f8\u6bd4\uff0cTFTP\u7684\u5927\u5c0f\u8981\u5c0f\u7684\u591a\u3002\u73b0\u5728\u6700\u666e\u904d\u4f7f\u7528\u7684\u662f\u7b2c\u4e8c\u7248 TFTP\uff08TFTP Version 2 , RFC 1350\uff09<\/p>\n<h4>TFTP\u534f\u8bae\u7ed3\u6784<\/h4>\n<p>\u56e0\u4e3aTFTP\u4f7f\u7528UDP\uff0c\u800cUDP\u4f7f\u7528IP\uff0cIP\u8fd8\u53ef\u4ee5\u4f7f\u7528\u5176\u5b83\u672c\u5730\u901a\u4fe1\u65b9\u6cd5\u3002\u56e0\u6b64\u4e00\u4e2aTFTP\u5305\u4e2d\u4f1a\u6709\u4ee5\u4e0b\u51e0\u6bb5\uff1a\u672c\u5730\u5a92\u4ecb\u5934\uff0cIP\u5934\uff0c\u6570\u636e\u62a5\u5934\uff0cTFTP\u5934\uff0c\u5269\u4e0b\u7684\u5c31\u662fTFTP\u6570\u636e\u4e86\u3002TFTP\u5728IP\u5934\u4e2d\u4e0d\u6307\u5b9a\u4efb\u4f55\u6570\u636e\uff0c\u4f46\u662f\u5b83\u4f7f\u7528UDP\u4e2d\u7684\u6e90\u548c\u76ee\u6807\u7aef\u53e3\u4ee5\u53ca\u5305\u957f\u5ea6\u57df\u3002\u7531TFTP\u4f7f\u7528\u7684\u5305\u6807\u8bb0\uff08TID\uff09\u5728\u8fd9\u91cc\u88ab\u7528\u505a\u7aef\u53e3\uff0c\u56e0\u6b64TID\u5fc5\u987b\u4ecb\u4e8e0\u523065,535\u4e4b\u95f4\u3002<br \/>\n\u6570\u636e\u5305\u7684\u7c7b\u578b\u6709\u4ee5\u4e0b\u4e94\u79cd\uff1a\u8bf7\u6c42\u8bfbRRQ\uff0c\u8bf7\u6c42\u5199WRQ\uff0c\u6587\u4ef6\u6570\u636eDATA\uff0c\u786e\u8ba4ACK\uff0c\u53d1\u751f\u9519\u8befERR\u3002\u62a5\u6587\u683c\u5f0f\u5982\u56fe<br \/>\n<img decoding=\"async\" src=\"https:\/\/i0.wp.com\/tihar-tech.cn\/wp-content\/uploads\/2019\/04\/java-tftp.png?w=1024\" alt=\"\" \/><\/p>\n<h4>TFTP\u5de5\u4f5c\u8fc7\u7a0b<\/h4>\n<p>TFTP\u7684\u5de5\u4f5c\u8fc7\u7a0b\u5f88\u50cf\u505c\u6b62\u7b49\u5f85\u534f\u8bae\uff0c\u53d1\u9001\u5b8c\u4e00\u4e2a\u6587\u4ef6\u5757\u540e\u5c31\u7b49\u5f85\u5bf9\u65b9\u7684\u786e\u8ba4\uff0c\u786e\u8ba4\u65f6\u5e94\u6307\u660e\u6240\u786e\u8ba4\u7684\u5757\u53f7\u3002\u53d1\u9001\u5b8c\u6570\u636e\u540e\u5728\u89c4\u5b9a\u65f6\u95f4\u5185\u6536\u4e0d\u5230\u786e\u8ba4\uff0c\u5c31\u8981\u91cd\u53d1\u6570\u636ePDU\uff0c\u53d1\u9001\u786e\u8ba4PDU\u7684\u4e00\u65b9\u82e5\u5728\u89c4\u5b9a\u65f6\u95f4\u5185\u6536\u4e0d\u5230\u4e0b\u4e00\u4e2a\u6587\u4ef6\u5757\uff0c\u4e5f\u8981\u91cd\u53d1\u786e\u8ba4PDU\u3002\u8fd9\u6837\u4fdd\u8bc1\u6587\u4ef6\u7684\u4f20\u9001\u4e0d\u81f4\u56e0\u67d0\u4e00\u4e2a\u6570\u636e\u62a5\u7684\u4e22\u5931\u800c\u544a\u5931\u8d25\u3002<\/p>\n<h4>\u5ba2\u6237\u7aef\u6267\u884c\u6b65\u9aa4<\/h4>\n<p>\u53d1\u9001RRQ\u6216WRQ\u8bf7\u6c42\u5230\u670d\u52a1\u5668\u768469\u7aef\u53e3\uff0c\u7b49\u5f85\u4e00\u4e2a\u6570\u636e\u5305\u6216\u8005\u662fACK\u5305\u3002\u8fd9\u4e2a\u5305\u5c06\u5305\u542b\u4e00\u4e2a69\u4ee5\u5916\u7684\u65b0\u7aef\u53e3\u53f7\u3002\u63a5\u6536\u5230\u6570\u636e\u5305\uff0c\u5c31\u4ee5ACK\u5305\u54cd\u5e94\uff0c\u63a5\u6536\u5230ACK\u5305\uff0c\u5c31\u53d1\u9001\u4e0b\u4e00\u4e2a\u6570\u636e\u5305\u3002\u51c6\u5907\u5904\u7406\u8d85\u65f6\u9519\u8bef\u6216\u8005\u662fERR\u5305\u3002<\/p>\n<h4>\u670d\u52a1\u7aef\u6267\u884c\u6b65\u9aa4<\/h4>\n<p>\u53d1\u9001RRQ\u6216WRQ\u8bf7\u6c42\u5230\u670d\u52a1\u5668\u768469\u7aef\u53e3\uff0c\u7b49\u5f85\u4e00\u4e2a\u6570\u636e\u5305\u6216\u8005\u662fACK\u5305\u3002\u8fd9\u4e2a\u5305\u5c06\u5305\u542b\u4e00\u4e2a69\u4ee5\u5916\u7684\u65b0\u7aef\u53e3\u53f7\u3002\u63a5\u6536\u5230\u6570\u636e\u5305\uff0c\u5c31\u4ee5ACK\u5305\u54cd\u5e94\uff0c\u63a5\u6536\u5230ACK\u5305\uff0c\u5c31\u53d1\u9001\u4e0b\u4e00\u4e2a\u6570\u636e\u5305\u3002\u51c6\u5907\u5904\u7406\u8d85\u65f6\u9519\u8bef\u6216\u8005\u662fERR\u5305\u3002<\/p>\n<h4>\u4ee3\u7801\u6d41\u7a0b\u56fe<\/h4>\n<p><img decoding=\"async\" src=\"https:\/\/i0.wp.com\/47.101.202.111\/wp-content\/uploads\/2019\/04\/java-tftp-progress-1247x993.png?resize=525%2C418\" alt=\"\" data-recalc-dims=\"1\" \/><\/p>\n<h4>\u5ba2\u6237\u7aef\u6e90\u7801<\/h4>\n<pre><code class=\"language-java\">\/\/UDP\u5ba2\u6237\u7aef\u521b\u5efaTFTP\u8bf7\u6c42\nclass UDPClient {\n\n    \/\/ OPCODES \u64cd\u4f5c\u7801\n    private static final byte RRQ_CODE = 1;\n    private static final byte WRQ_CODE = 2;\n    private static final byte DATA_CODE = 3;\n    private static final byte ACK_CODE = 4;\n    private static final byte ERR_CODE = 5;\n\n    \/\/ Connection variables\n    \/\/ \u6570\u636e\u62a5\u5927\u5c0f\n    private static int PACKET_SIZE = 516;\n    \/\/ \u7aef\u53e3\n    private static int PORT = 669;\n    \/\/ \u53d1\u9001\u7aef\u53e3\n    private static int SEND_PORT = 69;\n    \/\/ \u670d\u52a1\u5668\u7aef\u53e3\n    private int server_TID;\n\n    \/\/ \u5ba2\u6237\u7aef\u5957\u63a5\u5b57\n    private static DatagramSocket clientSocket;\n    \/\/ IP\u5730\u5740\n    private static InetAddress IPAddress;\n\n    \/\/ \u8bf7\u6c42\u5957\u63a5\u5b57\n    private static DatagramPacket request;\n    \/\/ \u6587\u4ef6\u8f93\u51fa\u6d41\n    private static ByteArrayOutputStream output;\n\n    \/\/ Error Codes\n    private static String ERROR_1 = &quot;File not found.&quot;;\n    private static String ERROR_2 = &quot;Access violation.&quot;;\n    private static String ERROR_3 = &quot;Disk Full.&quot;;\n    private static String ERROR_4 = &quot;Illegal TFTP operation.&quot;;\n    private static String ERROR_5 = &quot;Unknown Transfer ID.&quot;;\n    private static String ERROR_6 = &quot;File Already Exists.&quot;;\n    private static String ERROR_7 = &quot;No such user.&quot;;\n\n    \/\/ Client storage (R\/W) location\n    private static File outputFileDir;\n\n    \/**\n     * \n     * \u4e3b\u51fd\u6570\u5165\u53e3\n     * \n     * @param args\n     * @throws Exception\n     * \n     * \n     *\/\n\n    public static void main(String args[]) throws Exception {\n        \/\/ \u672c\u5730\u521b\u5efa\u6587\u4ef6\n        File currentDirectory = new File(new File(&quot;&quot;).getAbsolutePath());\n        outputFileDir = new File(currentDirectory.getAbsolutePath() + &quot;\\\\Client_Folder&quot;);\n        outputFileDir.mkdirs();\n        \/\/ \u521b\u5efa\u5ba2\u6237\u7aef\u5bf9\u8c61\u5e76\u8c03\u7528run\u51fd\u6570\n        UDPClient testClient = new UDPClient();\n        testClient.run();\n    }\n\n    \/**\n     * \u5ba2\u6237\u7aef\u8fd0\u884c\u51fd\u6570\n     *\/\n    private void run() {\n\n        \/\/ \u83b7\u53d6\u5b57\u7b26\u7f13\u51b2\u533a\u8f93\u5165\n        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));\n\n        \/\/ \u5f97\u5230 IP\n        try {\n            \/\/ IPAddress = InetAddress.getByName(&quot;localhost&quot;);\n            IPAddress = InetAddress.getByName(&quot;172.20.10.3&quot;);\n        } catch (UnknownHostException e1) {\n        }\n\n        \/\/ \u8f6e\u8be2\u7528\u6237\u8bf7\u6c42\n        while (true) {\n\n            \/\/ Assign a random TID for each request\n            try {\n                \/\/ \u968f\u673a\u751f\u6210\u4e34\u65f6\u901a\u4fe1\u6240\u7528\u7aef\u53e3\n                Random rand = new Random();\n                PORT = rand.nextInt(6536);\n                \/\/ \u4e0d\u4e3a\u7a7a\u4e14\u5df2\u7ed1\u5b9a\u5219\u5173\u95ed\u91cd\u542f\u4e00\u4e2a\u65b0\u7684clientsocket\n                if (clientSocket != null &amp;&amp; clientSocket.isBound()) {\n                    clientSocket.close();\n                }\n                clientSocket = new DatagramSocket(PORT);\n\n            } catch (SocketException e1) {\n                return;\n            }\n\n            System.out.println(&quot;Enter command: r\/w filename mode&quot;);\n            \/\/ Read user input\n            String sentence;\n            try {\n                \/\/ \u4ece\u8f93\u5165\u7f13\u51b2\u533a\u4e2d\u8bfb\u53d6\u4e00\u884c\n                sentence = inFromUser.readLine();\n                System.out.println(sentence);\n\n                \/\/ \u5224\u65ad\u9000\u51fa\n                if (sentence == &quot;quit&quot;) {\n                    break;\n                }\n\n                \/\/ \u83b7\u53d6\u7528\u6237\u8f93\u5165\u7684\u547d\u4ee4\u7684\u4e09\u90e8\u5206\n                String[] inputs = sentence.split(&quot; &quot;);\n                \/\/ \u5224\u65ad\u8f93\u5165\u662f\u5426\u975e\u6cd5\n                if (inputs.length == 3 &amp;&amp; (inputs[0].equals(&quot;r&quot;) || inputs[0].equals(&quot;w&quot;))\n                        &amp;&amp; (inputs[2].toLowerCase().equals(&quot;octet&quot;) || inputs[2].toLowerCase().equals(&quot;netascii&quot;))) {\n                    String fileName = inputs[1];\n                    String mode = inputs[2];\n                    mode = mode.toLowerCase();\n\n                    \/\/ \u8bfb\n                    if (inputs[0].equals(&quot;r&quot;)) {\n                        \/\/ \u521b\u5efa\u548c\u53d1\u9001 RRQ \u8bf7\u6c42\n                        DatagramPacket request1 = buildRequestPacket(RRQ_CODE, fileName, mode);\n                        clientSocket.send(request1);\n                        \/\/ \u4ece\u670d\u52a1\u5668\u83b7\u53d6\u6587\u4ef6\n                        get(inputs[1], inputs[2]);\n                    }\n                    \/\/ \u5199\n                    else if (inputs[0].equals(&quot;w&quot;)) {\n                        \/\/ \u521b\u5efa\u548c\u53d1\u9001 WRQ \u8bf7\u6c42\u6570\u636e\u62a5\u5305\n                        DatagramPacket request1 = buildRequestPacket(WRQ_CODE, fileName, mode);\n                        clientSocket.send(request1);\n\n                        \/\/ \u521b\u5efaACK\u6570\u636e\u62a5\n                        byte[] tempArray = new byte[516];\n                        DatagramPacket ackPacket = new DatagramPacket(tempArray, tempArray.length);\n\n                        \/\/ \u8f6e\u8be2\u670d\u52a1\u5668ACK\u54cd\u5e94\n                        while (true) {\n                            try {\n                                clientSocket.setSoTimeout(600000);\n                                clientSocket.receive(ackPacket);\n                                server_TID = ackPacket.getPort();\n                                \/\/ \u63a5\u6536\u5230ACK\u4ee5\u540e\u53d1\u9001\u6587\u4ef6\n                                sendFile(inputs[1], inputs[2]);\n                                break;\n                            } catch (SocketTimeoutException e) {\n                                \/\/ \u8d85\u65f6\u62a5\u9519\n                                System.out.println(&quot;Error, no response from server.&quot;);\n                            }\n                        }\n                    }\n                }\n                \/\/ \u8f93\u5165\u9519\u8bef\n                else {\n                    System.out.println(&quot;Invalid input&quot;);\n                }\n            } catch (Exception e) {\n                System.out.println(&quot;Error, invalid input&quot;);\n            }\n        }\n\n        \/\/ \u5b8c\u6bd5\u5173\u95ed\u5ba2\u6237\u7aef\u7aef\u53e3\n        clientSocket.close();\n\n    }\n\n    \/**\n     * \u4ece\u670d\u52a1\u5668\u8bfb\u53d6\u6587\u4ef6\n     * \n     * @param fileName\n     * @param mode\n     * @throws Exception\n     *\/\n    private void get(String fileName, String mode) throws Exception {\n\n        \/\/ \u6536\u5230\u6570\u636e\u62a5\n        output = receivePackets(fileName, mode);\n        \/\/ \u5982\u679c\u6536\u5230\u6570\u636e\u62a5\uff0c\u5199\u6587\u4ef6\u5230\u672c\u5730\n        if (output != null) {\n            writeFile(output, (fileName));\n        }\n    }\n\n    \/\/ \u521b\u5efa\u8bf7\u6c42\u6570\u636e\u62a5\n    DatagramPacket buildRequestPacket(byte requestType, String fileName, String mode) {\n\n        \/**\n         *     01\/02 \n         * -------------------------------------------------------------- | Opcode\n         * |  Filename |     0   |     Mode    |    0   |\n         * --------------------------------------------------------------- 2 bytes\n         *     string    1 byte       string      1 byte\n         * \n         *\/\n\n        byte zero = 0;\n        byte[] fileNameBytes = fileName.getBytes();\n        byte[] modeBytes = mode.getBytes();\n        int requestLength = 2 + (fileNameBytes.length) + 1 + (modeBytes.length) + 1;\n\n        \/\/ \u7a7f\u4ef6request\u6570\u636e\u62a5\u7f13\u51b2\u533a\u5e76\u586b\u5165\u5404\u5b57\u6bb5\u503c\n        ByteBuffer requestBuffer = ByteBuffer.allocate(requestLength);\n        requestBuffer.put(zero);\n        requestBuffer.put(requestType);\n        requestBuffer.put(fileNameBytes);\n        requestBuffer.put(zero);\n        requestBuffer.put(modeBytes);\n        requestBuffer.put(zero);\n\n        \/\/ \u8f6c\u4e3a\u5b57\u8282\u6570\u7ec4\u5e76\u6784\u5efa\u6570\u636e\u62a5\n        byte[] requestByteArray = requestBuffer.array();\n        DatagramPacket requestPacket = new DatagramPacket(requestByteArray, requestByteArray.length, IPAddress,\n                SEND_PORT);\n\n        \/\/ \u8fd4\u56de\u6570\u636e\u62a5\n        return requestPacket;\n    }\n\n    \/\/ \u53d1\u9001ACK\n    private void sendAcknowledgement(byte[] blockNumber, int portNumber) {\n\n        \/\/ \u521b\u5efa\u548c\u53d1\u9001ACK\u6570\u636e\u62a5\n        byte[] ackBytes = { (byte) 0, ACK_CODE, blockNumber[0], blockNumber[1] };\n        DatagramPacket ackPacket = new DatagramPacket(ackBytes, ackBytes.length, IPAddress, server_TID);\n        try {\n            \/\/ \u53d1\u9001\u6570\u636e\u62a5\n            clientSocket.send(ackPacket);\n        } catch (IOException e) {\n        }\n    }\n\n    \/\/ \u4ece\u670d\u52a1\u5668\u6536\u5230\u6570\u636e\u62a5\n    private ByteArrayOutputStream receivePackets(String fileName, String mode) throws IOException {\n\n        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();\n        int block = 1;\n        boolean packetsRemaining = true;\n        byte[] packetByteBuffer;\n        DatagramPacket receivedPacket;\n        boolean gotTID = false;\n\n        \/\/ \u6709\u5269\u4f59\u5219\u4e00\u76f4\u5faa\u73af\n        while (packetsRemaining) {\n\n            \/\/ \u5224\u65ad\u78c1\u76d8\u662f\u5426\u6ee1\n            if (outputFileDir.getTotalSpace() &lt; 516) {\n                sendError(3, ERROR_3, IPAddress, server_TID);\n                return null;\n            }\n\n            \/\/ \u83b7\u53d6\u6570\u636e\u62a5\n            packetByteBuffer = new byte[PACKET_SIZE];\n            receivedPacket = new DatagramPacket(packetByteBuffer, packetByteBuffer.length);\n\n            \/\/ Continue receiving until a valid packet is received\n            while (true) {\n                try {\n                    \/\/ 5s \u5ef6\u65f6 \u63a5\u6536\u5e76\u56de\u586b\n                    clientSocket.setSoTimeout(5000);\n                    clientSocket.receive(receivedPacket);\n\n                    \/\/ Ignore invalid ports\n                    if ((receivedPacket.getPort() != server_TID) &amp;&amp; gotTID) {\n                        sendError(5, ERROR_5, receivedPacket.getAddress(), receivedPacket.getPort());\n                    } else {\n                        break;\n                    }\n                } catch (SocketTimeoutException e) {\n                    \/\/ \u670d\u52a1\u5668\u65e0\u54cd\u5e94\n                    if (block == 1) {\n                        System.out.println(&quot;Error, no response from server.&quot;);\n                        return null;\n                    }\n                    \/\/ \u83b7\u53d6\u4e0a\u4e00\u4e2ablock\u9ad88\u4f4d\u548c\u4f4e8\u4f4d\n                    byte blockMSB = (byte) (((block - 1) &gt;&gt;&gt; 8) &amp; 0xFF);\n                    byte blockLSB = (byte) (((block - 1)) &amp; 0xFF);\n                    byte[] blockBytes = { blockMSB, blockLSB };\n                    \/\/ \u91cd\u65b0\u53d1\u9001ACK\n                    sendAcknowledgement(blockBytes, server_TID);\n                }\n            }\n\n            \/\/ \u53d6\u5f97\u670d\u52a1\u7aef\u7aef\u53e3\n            if (!gotTID) {\n                server_TID = receivedPacket.getPort();\n                gotTID = true;\n            }\n\n            \/\/ netascii\u91cd\u65b0\u7f16\u7801\n            if (mode.equals(&quot;netascii&quot;)) {\n                String temp = new String(packetByteBuffer);\n                packetByteBuffer = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                temp = new String(packetByteBuffer);\n            }\n\n            \/\/ \u53d6\u64cd\u4f5c\u7801\u5224\u65ad\u7c7b\u578b\n            byte opCode = packetByteBuffer[1];\n            if (opCode == DATA_CODE) {\n\n                \/\/ \u68c0\u67e5\u957f\u5ea6\uff0c\u82e5\u5c0f\u4e8e516\u5219\u4e3a\u6700\u540e\u4e00\u4e2a\u6570\u636e\u62a5\uff0c\u7f6e\u5faa\u73af\u6761\u4ef6\u4e3afalse\n                if (receivedPacket.getLength() &lt; 516) {\n                    packetsRemaining = false;\n\n                    \/\/ \u5224\u65ad\u6587\u4ef6\u662f\u5426\u5df2\u7ecf\u5b58\u5728\n                    File fileOut1 = new File(outputFileDir.getAbsoluteFile() + &quot;\\\\&quot; + fileName);\n                    if (fileOut1.exists()) {\n                        sendError(6, ERROR_6, IPAddress, server_TID);\n                        return null;\n                    }\n                }\n\n                \/\/ \u53d6\u5f97\u5757\u53f7\n                byte[] temp = { (packetByteBuffer[2]), packetByteBuffer[3] };\n                int number = (((packetByteBuffer[2] &amp; 0xFF) &lt;&lt; 8) + (packetByteBuffer[3] &amp; 0xFF)) &amp; 0xFFFF;\n\n                \/\/ \u5c06\u6570\u636e\u90e8\u5206\u5199\u5165\u8f93\u51fa\u6d41\n                DataOutputStream dataOut = new DataOutputStream(byteOutputStream);\n                dataOut.write(packetByteBuffer, 4, receivedPacket.getLength() - 4);\n\n                \/\/ \u53d1\u9001ACK \u5757\u53f7+1\n                sendAcknowledgement(temp, server_TID);\n                block++;\n            }\n            \/\/ \u9519\u8bef\u4fe1\u606f\u6570\u636e\u62a5\n            else if (opCode == ERR_CODE) {\n                \/\/ \u5206\u7247\u5206\u51fa\u9519\u8bef\u4fe1\u606f\u5e76\u6253\u5370\u8f93\u51fa\n                packetByteBuffer[1] = (byte) 0;\n                packetByteBuffer[3] = (byte) 0;\n                byte[] zeroByteArray = { 0 };\n                String zeroString = new String(zeroByteArray);\n                String errorMessage = new String(packetByteBuffer);\n                String[] splitMessage = errorMessage.split(zeroString);\n                System.out.println(&quot;Error : &quot; + splitMessage[4]);\n                return null;\n            } \/\/ \u5176\u4ed6\u9519\u8bef\n            else {\n                sendError(0, &quot;undefined error&quot;, IPAddress, server_TID);\n                return null;\n            }\n        }\n        \/\/\u8fd4\u56de\u8f93\u51fa\u6d41\n        return byteOutputStream;\n    }\n\n    \/\/ \u5ba2\u6237\u7aef\u5199\u6587\u4ef6\n    private void writeFile(ByteArrayOutputStream byteOutputStream, String fileName) {\n        try {\n            \/\/\u5199\u6587\u4ef6\u5e76\u5173\u95ed\u8f93\u51fa\u6d41\n            OutputStream outputStream = new FileOutputStream(outputFileDir + &quot;\\\\&quot; + fileName);\n            byteOutputStream.writeTo(outputStream);\n            byteOutputStream.close();\n            outputStream.close();\n\n            \/\/ \u5b8c\u6210\u6821\u9a8c\u548c\u8ba1\u7b97\n            MessageDigest md = MessageDigest.getInstance(&quot;MD5&quot;);\n            InputStream is = Files.newInputStream(Paths.get(outputFileDir + &quot;\\\\&quot; + fileName));\n            DigestInputStream dis = new DigestInputStream(is, md);\n            \/\/ \u8bfb\u5230\u6587\u4ef6\u672b\u5c3e\n            while ((is.read()) != -1) {\n            }\n            String digest = new String(md.digest());\n            System.out.println(&quot;checksum : &quot; + digest);\n            is.close();\n\n        } catch (FileAlreadyExistsException e) {\n            System.out.println(&quot;File already exists.&quot;);\n\n        } catch (IOException e) {\n            System.out.println(&quot;Error writing file.&quot;);\n        } catch (NoSuchAlgorithmException e) {\n            System.out.println(&quot;Error writing file.&quot;);\n        }\n    }\n\n    \/\/ \u5411\u670d\u52a1\u7aef\u53d1\u9001\u6587\u4ef6\n    void sendFile(String fileName, String mode) throws IOException {\n        \/\/ \u5df2\u7ecf\u6536\u5230ACK\u7684\u60c5\u51b5\u4e0b \u8981\u5411\u670d\u52a1\u7aef\u53d1\u9001\u7b2c\u4e00\u5757\u6570\u636e\n        int block = 1;\n        int bytesRead = 0;\n        boolean serverTIDCollected = false;\n\n        try {\n\n            \/\/ \u5199\u6587\u4ef6\n            File file = new File(outputFileDir + &quot;\\\\&quot; + fileName);\n            long length = file.length();\n            InputStream in = new FileInputStream(file);\n            byte[] bytes = new byte[512];\n            byte[] bytesToRead = new byte[516];\n\n            \/\/ \u53ea\u8981\u4ecd\u7136\u53ef\u8bfb\uff0c\u7f13\u51b2\u533a\u6bcf\u6b21\u8bfb512B\n            while ((bytesRead = in.read(bytes, 0, 512)) != -1) {\n\n                int size = bytesRead + 4;\n\n                \/\/ \u7f13\u51b2\u533a\u5199\u5165 03+\u5757\u53f7+\u6570\u636e \u8f6c\u4e3a\u5b57\u8282\u6570\u7ec4 \u7ec4\u88c5\u6210\u53d1\u9001\u6570\u636e\u62a5\n                ByteBuffer sendBuffer = ByteBuffer.allocate(size);\n                sendBuffer.put((byte) 0);\n                sendBuffer.put((byte) 3);\n                sendBuffer.put((byte) (block &gt;&gt;&gt; 8));\n                sendBuffer.put((byte) (block &amp; 0xFF));\n                sendBuffer.put(bytes, 0, bytesRead);\n\n                byte[] bytesToSend = sendBuffer.array();\n\n                \/\/ netascii\u7f16\u7801\u8f6c\u6362\n                if (mode.equals(&quot;netascii&quot;)) {\n                    String temp = new String(bytesToSend);\n                    bytesToSend = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                    temp = new String(bytesToSend);\n                }\n                \/\/ \u7ec4\u88c5\u53d1\u9001\u6570\u636e\u5305 -----------bytesToSend\n                DatagramPacket sendPacket = new DatagramPacket(bytesToSend, bytesToSend.length, IPAddress, server_TID);\n\n                \/\/ \u53d1\u9001\u6570\u636e\u62a5\n                clientSocket.send(sendPacket);\n                \/\/ \u7ec4\u88c5\u63a5\u6536\u6570\u636e\u5305ACK -----------bytesToRead\n                DatagramPacket receivePacket = new DatagramPacket(bytesToRead, bytesToRead.length);\n\n                \/\/ \u8f6e\u8be2\u7b49\u5f85\u54cd\u5e94\n                while (true) {\n                    try {\n                        \/\/ \u8bbe\u7f6e\u5ef6\u65f650s \u63a5\u6536ACK\u5e76\u56de\u586bbytesToRead\n                        clientSocket.setSoTimeout(50000);\n                        clientSocket.receive(receivePacket);\n                        \/\/ \u5982\u679c\u548c\u670d\u52a1\u7aef\u7aef\u53e3\u4e0d\u5408\u62a5\u9519\n                        if (receivePacket.getPort() != server_TID &amp;&amp; serverTIDCollected) {\n                            sendError(5, ERROR_5, receivePacket.getAddress(), receivePacket.getPort());\n                        } else {\n                            \/\/ \u7aef\u53e3\u76f8\u540c\u4f20\u8f93\u6b63\u786e\uff0c\u8df3\u51fa\u8f6e\u8be2\n                            break;\n                        }\n\n                    } \/\/ \u8d85\u65f6\u91cd\u4f20\u53d1\u9001\u6570\u636e\u62a5\n                    catch (SocketTimeoutException e) {\n                        clientSocket.send(sendPacket);\n                    }\n                }\n\n                \/\/ \u83b7\u53d6\u670d\u52a1\u7aef\u7aef\u53e3\n                if (!serverTIDCollected) {\n                    server_TID = receivePacket.getPort();\n                    serverTIDCollected = true;\n                }\n\n                \/\/ netascii\u7f16\u7801\n                if (mode.equals(&quot;netascii&quot;)) {\n                    String temp = new String(bytesToRead);\n                    bytesToRead = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                    temp = new String(bytesToRead);\n                }\n\n                \/\/ \u4ece\u670d\u52a1\u5668\u54cd\u5e94\u56de\u586b\u7684bytesToRead\u4e2d\u8bfb\u51fa\u54cd\u5e94\u6570\u636e\u62a5\u7c7b\u578b\n                switch (bytesToRead[1]) {\n                \/\/ \u8bfb\u53d6ACK\u5757\u53f7 \u5757\u53f7\u4e0d\u5339\u914d\u62a5\u9519 \u5339\u914d\u5219\u81ea\u589e\u5230\u4e0b\u4e00\u5757 \u9000\u51faswitch\n                case ACK_CODE:\n                    int temp = ((bytesToRead[2] &amp; 0xFF) &lt;&lt; 8) + (bytesToRead[3] &amp; 0xFF);\n                    if (temp != block) {\n                        sendError(0, &quot;Incorrent Block&quot;, IPAddress, server_TID);\n                    } else {\n                        block++;\n                    }\n                    break;\n                \/\/ \u7247\u51faERR\u9519\u8bef\u6d88\u606f\u5e76\u6253\u5370\uff0c\u8df3\u51fasendFile\u51fd\u6570\n                case ERR_CODE:\n                    bytesToRead[1] = (byte) 0;\n                    bytesToRead[3] = (byte) 0;\n                    byte[] zeroByteArray = { 0 };\n                    String zeroString = new String(zeroByteArray);\n                    String errorMessage = new String(bytesToRead);\n                    String[] splitMessage = errorMessage.split(zeroString);\n                    System.out.println(&quot;Error : &quot; + splitMessage[4]);\n                    in.close();\n                    return;\n\n                \/\/ \u4e0d\u652f\u6301\u7684\u7c7b\u578b\u62a5\u9519\n                default:\n                    sendError(4, ERROR_4, IPAddress, server_TID);\n                    in.close();\n                    return;\n                }\n            }\n            in.close();\n\n        } catch (FileNotFoundException e) {\n            sendError(1, ERROR_1, IPAddress, server_TID);\n        } catch (IOException e) {\n            System.out.println(&quot;Error reading file&quot;);\n            return;\n        }\n    }\n\n    \/\/ \u53d1\u9001\u9519\u8bef\u6570\u636e\u62a5\n    void sendError(int errorCode, String errorMessage, InetAddress address, int port) {\n\n        \/\/ \u6253\u5370\u9519\u8bef\u4fe1\u606f \n        System.out.println(&quot;Error &quot; + errorMessage);\n        byte code = (byte) (errorCode &amp; 0xFF);\n        byte[] message = errorMessage.getBytes();\n\n        \/**   05        0+code     msg     0\n         * -----------------------------------------------\n         * | Opcode | ErrorCode | ErrMsg | 0 |\n         * -----------------------------------------------\n         * 2 bytes   2 bytes     string  1 byte\n         *\/\n        int size = 5 + message.length;\n        ByteBuffer error = ByteBuffer.allocate(size);\n        error.put((byte) 0);\n        error.put((byte) 5);\n        error.put((byte) 0);\n        error.put(code);\n        error.put(message);\n        error.put((byte) 0);\n\n        \/\/\u7ec4\u88c5\u6210\u9519\u8bef\u6570\u636e\u62a5\u5e76\u53d1\u9001\n        DatagramPacket errorPacket = new DatagramPacket(error.array(), error.array().length, address, port);\n        try {\n            clientSocket.send(errorPacket);\n        } catch (IOException e) {\n            System.out.println(&quot;Error sending error&quot;);\n        }\n        System.out.println(&quot;Client Error :&quot; + errorMessage);\n    }\n\n}<\/code><\/pre>\n<h4>\u670d\u52a1\u7aef\u6e90\u7801<\/h4>\n<pre><code class=\"language-java\">class UDPServer {\n\n    \/\/ OPCODES \u62a5\u6587\u8bc6\u522b\u7801 byte\u7c7b\u578b\n    \/\/ \u8bf7\u6c42\u8bfb\n    private static final byte RRQ = 1;\n    \/\/ \u8bf7\u6c42\u5199\n    private static final byte WRQ = 2;\n    \/\/ \u4f20\u9001\u6570\u636e\n    private static final byte DATA = 3;\n    \/\/ \u786e\u8ba4\u62a5\u6587\n    private static final byte ACK = 4;\n    \/\/ \u9519\u8bef\u62a5\u6587\n    private static final byte ERR = 5;\n\n    \/\/ \u6570\u636e\u62a5\u957f\u5ea6512 B + \u5934\u957f\u5ea64 B = 516 B\n    private static int PACKET_SIZE = 516;\n\n    \/\/ Sockets\n    \/\/ UDP\u534f\u8bae\u7684Socket \u6570\u636e\u62a5\n    \/\/ \u670d\u52a1\u7aef\u6570\u636e\u62a5\n    static DatagramSocket serverSocket;\n    \/\/ \u8bf7\u6c42\u6570\u636e\u62a5\n    static DatagramSocket requestSocket;\n    \/\/ \u6570\u5b57\u5f62\u5f0f\u4fdd\u5b58\u7684IP\u5730\u5740\n    private static InetAddress IPAddress;\n\n    \/\/ Ports\n    \/\/ \u670d\u52a1\u5668\u7aef\u53e369\n    private static int SERVER_PORT = 69;\n    \/\/ \u5ba2\u6237\u7aef\u7aef\u53e3669\n    private static int CLIENT_PORT = 669;\n\n    \/\/ Error IDs \u9519\u8bef\u4fe1\u606f\n    \/\/ \u6587\u4ef6\u672a\u627e\u5230\n    private static String ERROR_1 = &quot;File not found.&quot;;\n    \/\/ \u8bbf\u95ee\u975e\u6cd5\n    private static String ERROR_2 = &quot;Access violation.&quot;;\n    \/\/ \u78c1\u76d8\u5df2\u6ee1\n    private static String ERROR_3 = &quot;Disk Full.&quot;;\n    \/\/ \u975e\u6cd5TFTP\u64cd\u4f5c\n    private static String ERROR_4 = &quot;Illegal TFTP operation.&quot;;\n    \/\/ \u672a\u77e5\u4f20\u8f93ID\n    private static String ERROR_5 = &quot;Unknown Transfer ID.&quot;;\n    \/\/ \u6587\u4ef6\u5df2\u5b58\u5728\n    private static String ERROR_6 = &quot;File Already Exists.&quot;;\n    \/\/ \u65e0\u6b64\u7528\u6237\n    private static String ERROR_7 = &quot;No such user.&quot;;\n\n    \/\/ \u5b57\u8282\u6570\u7ec4\u8f93\u51fa\u6d41\n    private static ByteArrayOutputStream output;\n\n    \/\/ TIDs\n    \/\/ \u76ee\u7684\u7aef\u53e3\n    private int destination_TID;\n    \/\/ \u5f53\u524d\u7aef\u53e3\n    private int current_TID;\n\n    \/\/ Server file storage location \u8f93\u51fa\u6587\u4ef6\u76ee\u5f55\n    static File outputFileDir;\n\n    public static void main(String args[]) throws Exception {\n        \/\/ UDPserver\u5b9e\u4f8b\u5316\n        UDPServer testServer = new UDPServer();\n        \/\/ Create and locate the storage directory \u6839\u636e\u5f53\u524d\u7edd\u5bf9\u8def\u5f84\u521b\u5efa\u65b0\u6587\u4ef6\n        File currentDirectory = new File(new File(&quot;&quot;).getAbsolutePath());\n        \/\/ \u521b\u5efa\u8f93\u51fa\u6587\u4ef6Server_Folder\n        outputFileDir = new File(currentDirectory.getAbsolutePath() + &quot;\\\\Server_Folder\\\\&quot;);\n        \/\/ \u521b\u5efa\u8f93\u51fa\u6587\u4ef6\u76ee\u5f55\n        outputFileDir.mkdirs();\n        \/\/ Run the server \u8df3\u5230run\u51fd\u6570\n        testServer.run();\n\n    }\n\n    \/**\n     * \u8fd0\u884cserver\u7aef\n     * \n     * @throws Exception\n     *\/\n    void run() throws Exception {\n\n        System.out.println(&quot;Server Started&quot;);\n        \/\/ \u5f00\u542f69\u7aef\u53e3\u5904\u7406\u5ba2\u6237\u7aef\u8bf7\u6c42\n        try {\n            \/\/ \u521b\u5efa\u4e00\u4e2aDatagramSocket\u5b9e\u4f8b\uff0c\u5e76\u5c06\u8be5\u5bf9\u8c61\u7ed1\u5b9a\u5230\u672c\u673a\u9ed8\u8ba4IP\u5730\u5740\u300169\u7aef\u53e3\u3002\n            requestSocket = new DatagramSocket(69);\n        } catch (SocketException e) {\n            e.printStackTrace();\n        }\n        \/\/ Data arrays and packets\n        \/\/ \u8bf7\u6c42\u6570\u636e\u5b57\u8282\u6570\u7ec4\n        byte[] requestData = new byte[516];\n        \/\/ \u6784\u9020 DatagramPacket\uff0c\u7528\u6765\u8bf7\u6c42\u957f\u5ea6\u4e3a 516 \u7684\u6570\u636e\u5305\n        DatagramPacket request = new DatagramPacket(requestData, requestData.length);\n        \/\/ \u63a5\u6536\u6570\u636e\u5b57\u8282\u6570\u7ec4\n        byte[] receiveData = new byte[100];\n        \/\/ \u53d1\u9001\u6570\u636e\u5b57\u8282\u6570\u7ec4\n        byte[] sendData = new byte[1024];\n\n        \/\/ \u957f\u8f6e\u8be2 \u7b49\u5f85\u8bf7\u6c42\n        while (true) {\n            try {\n                System.out.println(&quot;Server waiting for requests&quot;);\n                \/\/ \u7b49\u5f85\u8bf7\u6c42\u5e76\u52a0\u8f7d\u5165receivePacket\n                \/\/ \u6784\u9020 DatagramPacket\uff0c\u7528\u6765\u63a5\u6536\u957f\u5ea6\u4e3a 100\u7684\u6570\u636e\u5305\n                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);\n                \/\/ \u4ece\u6b64\u5957\u63a5\u5b57\u63a5\u6536\u6570\u636e\u62a5 UDP\u6570\u636e\u62a5\u5c31\u662f\u5957\u63a5\u5b57 \u82e5\u672a\u63a5\u6536\u6210\u529f\u5219\u4e0d\u5f80\u4e0b\u8fd0\u884c\u4e0b\u4e00\u884c\u4ee3\u7801\n                requestSocket.receive(receivePacket);\n\n                System.out.println(&quot;Request Received&quot;);\n\n                \/**\n                 * \n                 * WRQ\/RRQ\u6570\u636e\u62a5\u683c\u5f0f\n                 * \n                 * \n                 * 01 \/ 02 \n                 * -------------------------------------------------------------- |\n                 * Opcode | Filename | 0 | Mode | 0 |\n                 * --------------------------------------------------------------- 2 bytes\n                 * string 1 byte string 1 byte\n                 * \n                 *\/\n\n                \/\/ \u51b3\u5b9a\u63a5\u53d7\u6570\u636e\u62a5\u7c7b\u578b\n                \/\/\u63a5\u6536\u6570\u636e\u5b57\u8282\u6570\u7ec4\u7c7b\u578b\uff0c\u64cd\u4f5c\u7801\u4e3a\u7b2c2\u4e2a\u5b57\u8282\n                byte opCodeReceived = receiveData[1];\n                \/\/ 0\u6bd4\u7279\u6570\u7ec4 \u957f\u5ea6\u4e3a1 \u5185\u5bb9\u4e3a0\n                byte[] zeroByte = { 0 };\n                \/\/ \u8f6c\u4e3a\u5b57\u7b26\u4e32\u578b\n                String zeroString = new String(zeroByte);\n                \/\/ \u63a5\u6536\u6570\u636e\u5b57\u8282\u6570\u7ec4\u7b2c2\u4e2a\u5b57\u8282\uff089-16\u4f4d\uff09\u8bbe\u7f6e\u4e3a0\n                receiveData[1] = zeroByte[0];\n                \/\/ \u63a5\u6536\u6570\u636e\u5b57\u7b26\u4e32\n                String inputString = new String(receiveData);\n                \/\/ \u6839\u636e0\u6bd4\u7279\u5b57\u7b26\u4e32\u5206\u6bb5\u653e\u5165pieces\u6570\u7ec4\n                String[] pieces = inputString.split(zeroString);\n                \/\/ pieces\u6570\u7ec4\u7b2c3\u6bb5\u8bbe\u7f6e\u4e3a\u6587\u4ef6\n                String fileString = pieces[2];\n                \/\/ pieces\u6570\u7ec4\u7b2c4\u6bb5\u8bbe\u7f6e\u4e3a\u6a21\u5f0f\n                String mode = pieces[3];\n                \/\/ \u5c06\u5927\u5199\u5b57\u7b26\u8f6c\u6362\u4e3a\u5c0f\u5199\n                mode = mode.toLowerCase();\n\n                \/\/ \u83b7\u53d6\u5ba2\u6237\u7aefIP\u548c\u7aef\u53e3\n                \/\/ \u8fd4\u56de\u67d0\u53f0\u673a\u5668\u7684 IP \u5730\u5740\uff0c\u6b64\u6570\u636e\u62a5\u5c06\u8981\u53d1\u5f80\u8be5\u673a\u5668\u6216\u8005\u662f\u4ece\u8be5\u673a\u5668\u63a5\u6536\u5230\u7684\n                IPAddress = receivePacket.getAddress();\n                \/\/ \u83b7\u53d6\u5ba2\u6237\u7aef\u7aef\u53e3\u53f7\n                CLIENT_PORT = receivePacket.getPort();\n\n                \/\/ \u7ed9\u670d\u52a1\u7aef\u6307\u5b9a\u4e00\u4e2a\u968f\u673a\u6570 TID\n                Random rand = new Random();\n                \/\/ \u968f\u673a\u751f\u62100-6535\u7684\u968f\u673a\u6570\n                current_TID = rand.nextInt(6535);\n                \/\/ \u548c\u7aef\u53e3\u53f7\u76f8\u540c\u81ea\u589e\n                if (current_TID == CLIENT_PORT) {\n                    current_TID++;\n                }\n                \/\/ Opens the TID socket \u521b\u5efa\u6570\u636e\u62a5\u5957\u63a5\u5b57\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u672c\u5730\u4e3b\u673a\u4e0a\u7684\u6307\u5b9a\u7aef\u53e3\n                serverSocket = new DatagramSocket(current_TID);\n\n                \/\/ Handles the received input type \u8f93\u5165\u7c7b\u578b\u5206\u53d1\n                switch (opCodeReceived) {\n                \/\/ Read request \u8bfb\u8bf7\u6c42\n                case RRQ:\n                    System.out.println(&quot;Sending File for read request&quot;);\n                    \/\/ Sends a requested file to the user from storage\n                    sendFile(fileString, mode);\n                    break;\n                \/\/ Write request \u5199\u8bf7\u6c42\n                case WRQ:\n                    System.out.println(&quot;Receiving File from write request&quot;);\n                    \/\/ Obtains and writes a user file to the server storage\n                    get(fileString, mode);\n                    break;\n                \/\/ Handles error messages \u5904\u7406\u9519\u8bef\u4fe1\u606f\n                case ERR:\n                    \/\/ Formats input to obtain error message\n                    receiveData[1] = (byte) 0;\n                    receiveData[3] = (byte) 0;\n                    byte[] zeroByteArray = { 0 };\n                    String errorMessage = new String(receiveData);\n                    String[] splitMessage = errorMessage.split(zeroString);\n                    System.out.println(&quot;Error : &quot; + splitMessage[4]);\n                    break;\n                \/\/ If unacknowledged data type is received, respond with an error message \u672a\u77e5\u7c7b\u578b\n                default:\n                    sendError(4, ERROR_4, IPAddress, CLIENT_PORT);\n                    break;\n                }\n                \/\/ Close the socket when finished\n                serverSocket.close();\n\n                \/\/ QUit the server if the quit command is issued\n                if (mode == &quot;quit&quot;) {\n                    break;\n                }\n\n            } catch (NullPointerException e) {\n                sendError(0, &quot;Undefined&quot;, IPAddress, CLIENT_PORT);\n            }\n        }\n\n        \/\/ Close the server socket when finished\n        requestSocket.close();\n\n    }\n\n    \/\/ Sends a file to a client\n    \/**\n     * \u53d1\u9001\u6587\u4ef6\n     * \n     * @param fileName\n     * @param mode\n     *\/\n    void sendFile(String fileName, String mode) {\n\n        \/\/ Number of blocks received and bytes read\n        int block = 1;\n        int bytesRead = 0;\n\n        try {\n\n            \/\/ Opens reference to desired file\n            File file;\n            try {\n                file = new File(outputFileDir.getAbsolutePath() + &quot;\\\\&quot; + fileName);\n            } catch (Exception e) {\n                \/\/ Notify the user if it is not found, the search for clients again\n                sendError(1, ERROR_1, IPAddress, CLIENT_PORT);\n                return;\n            }\n\n            \/\/ If the file exists send it to the client\n            if (file.exists()) {\n\n                \/**\n                 * \n                 * ----------------------------------- | Opcode | Block # | Data |\n                 * ----------------------------------- 2 bytes 2 bytes n bytes\n                 * \n                 * \n                 *\/\n\n                \/\/ File IO variables\n                InputStream in = new FileInputStream(file);\n                byte[] bytes = new byte[512];\n                byte[] bytesToRead = new byte[516];\n\n                \/\/ Checksum computation\n                MessageDigest md = MessageDigest.getInstance(&quot;MD5&quot;);\n                \/\/ \u521b\u5efaMD5\u8f93\u5165\u6d41\n                \/**\n                 * \n                 * \n                 * --------------------------------------------------------------------------------------------------------------------\n                 * \n                 * \n                 *\/\n                DigestInputStream dis = new DigestInputStream(in, md);\n\n                \/\/ Read till the end of the file, storing read data into bytes, in 512 byte\n                \/\/ chunks \u4e00\u76f4\u8bfb\u5230\u5c3e\u90e8 \u8bfb\u53d6512\u4e2a\u5b57\u8282\u5b58\u5230\u4ecebytes[0]\u5f00\u59cb\u7684\u5b57\u8282\u7f13\u51b2\u533a\u5e76\u4fdd\u5b58 \u8fd4\u56de\u6210\u529f\u8bfb\u53d6\u7684\u5b57\u8282\u6570\n                while ((bytesRead = in.read(bytes, 0, 512)) != -1) {\n                    \/\/ Determine packet size\n                    int size = bytesRead + 4;\n\n                    \/\/ Buffer data into bytesToSend \u4ece\u5806\u7a7a\u95f4\u4e2d\u5206\u914d\u4e00\u4e2a\u5bb9\u91cf\u5927\u5c0f\u4e3asize 516\u7684byte\u6570\u7ec4\u4f5c\u4e3a\u7f13\u51b2\u533a\u7684byte\u6570\u636e\u5b58\u50a8\u5668\n                    ByteBuffer sendBuffer = ByteBuffer.allocate(size);\n                    \/\/ \u76f8\u5bf9\u5199\uff0c\u54110\u7684\u4f4d\u7f6e\u5199\u5165\u4e00\u4e2abyte\uff0c\u5e76\u5c06postion+1\uff0c\u4e3a\u4e0b\u6b21\u8bfb\u5199\u4f5c\u51c6\u5907\n                    sendBuffer.put((byte) 0);\n                    sendBuffer.put((byte) 3);\n                    \/\/ \u65e0\u7b26\u53f7\u53f3\u79fb\uff0c\u5ffd\u7565\u7b26\u53f7\u4f4d\uff0c\u7a7a\u4f4d\u90fd\u4ee50\u8865\u9f50 \u5199\u5165block\u5757\u6570\n                    sendBuffer.put((byte) (block &gt;&gt;&gt; 8));\n                    sendBuffer.put((byte) (block &amp; 0xFF));\n                    \/\/ \u4ecesrc\u6570\u7ec4\u4e2d\u7684bytes\u5230offset+length\u533a\u57df\u8bfb\u53d6\u6570\u636e\u5e76\u4f7f\u7528\u76f8\u5bf9\u5199\u5199\u5165\u6b64byteBuffer\n                    sendBuffer.put(bytes, 0, bytesRead);\n                    byte[] bytesToSend = sendBuffer.array();\n\n                    \/\/ If in netascii mode, encode data appropriately \u4ec5\u652f\u6301txt\u6587\u4ef6\n                    if (mode.equals(&quot;netascii&quot;)) {\n                        String temp = new String(bytesToSend);\n                        bytesToSend = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                        temp = new String(bytesToSend);\n                    }\n                    \/\/ Make Packet\n                    DatagramPacket sendPacket = new DatagramPacket(bytesToSend, bytesToSend.length, IPAddress,\n                            CLIENT_PORT);\n\n                    \/\/ Send Packet\n                    serverSocket.send(sendPacket);\n\n                    \/\/ Wait for Acknowledgement of last block, otherwise resend last packet\n\n                    DatagramPacket receivePacket = new DatagramPacket(bytesToRead, bytesToRead.length, IPAddress,\n                            SERVER_PORT);\n                    \/\/ Wait until a valid packet is received\n                    while (true) {\n                        try {\n                            \/\/ Set timeout to 50s\n                            serverSocket.setSoTimeout(50000);\n                            serverSocket.receive(receivePacket);\n                            \/\/ Ignore data from incorrect ports, and send them an error message\n                            if (receivePacket.getPort() != CLIENT_PORT) {\n                                sendError(5, ERROR_5, receivePacket.getAddress(), receivePacket.getPort());\n                            } else {\n                                break;\n                            }\n                        } catch (SocketTimeoutException e) {\n                            serverSocket.send(sendPacket);\n                        }\n                    }\n\n                    \/\/ Encode data if in netascii mode\n                    if (mode.equals(&quot;netascii&quot;)) {\n                        String temp = new String(bytesToRead);\n                        bytesToRead = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                        temp = new String(bytesToRead);\n                    }\n\n                    \/\/ Determine received packet type and respond\n                    switch (bytesToRead[1]) {\n                    case ACK:\n                        \/\/ Determine which block was acknowledged\n                        int temp = ((bytesToRead[2] &amp; 0xFF) &lt;&lt; 8) + (bytesToRead[3] &amp; 0xFF);\n                        if (temp != block) {\n                            System.out.println(&quot;INCORRECT BLOCK&quot;);\n                        }\n                        \/\/ Increment the block count\n                        else {\n                            block++;\n                        }\n                        break;\n                    \/\/ Handle error messages\n                    case ERR:\n                        \/\/ Format data to obtain error message\n                        bytesToRead[1] = (byte) 0;\n                        bytesToRead[3] = (byte) 0;\n                        byte[] zeroByteArray = { 0 };\n                        String zeroString = new String(zeroByteArray);\n                        String errorMessage = new String(bytesToRead);\n                        String[] splitMessage = errorMessage.split(zeroString);\n                        System.out.println(&quot;Error : &quot; + splitMessage[4]);\n                        return;\n                    \/\/ Handle non accepted data type with an error message\n                    default:\n                        sendError(4, ERROR_4, IPAddress, CLIENT_PORT);\n                        return;\n                    }\n                }\n\n                \/\/ Display checksum and close streams\n                String digest = new String(md.digest());\n                System.out.println(&quot;Data chucksum: &quot; + digest);\n                in.close();\n\n            } else {\n                \/\/ Handle file not found errors\n                sendError(1, ERROR_1, IPAddress, CLIENT_PORT);\n            }\n        }\n        \/\/ Handle file not found errors\n        catch (FileNotFoundException e) {\n            sendError(1, ERROR_1, IPAddress, CLIENT_PORT);\n        }\n        \/\/ Handle file not found errors\n        catch (IOException e) {\n            sendError(1, ERROR_1, IPAddress, CLIENT_PORT);\n            return;\n        }\n        \/\/ Handle checksum errors\n        catch (NoSuchAlgorithmException e) {\n            sendError(0, &quot;Checksum error.&quot;, IPAddress, CLIENT_PORT);\n            return;\n        }\n    }\n\n    \/\/ Send an error message to the client\n    void sendError(int errorCode, String errorMessage, InetAddress address, int port) {\n\n        \/\/ Encode the error message\n        byte code = (byte) (errorCode &amp; 0xFF);\n        byte[] message = errorMessage.getBytes();\n\n        \/**\n         * 05 ----------------------------------------------- | Opcode | ErrorCode |\n         * ErrMsg | 0 | ----------------------------------------------- 2 bytes 2 bytes\n         * string 1 byte\n         * \n         *\/\n        \/\/ Buffer the error message as bytes\n        int size = 5 + message.length;\n        ByteBuffer error = ByteBuffer.allocate(size);\n        error.put((byte) 0);\n        error.put((byte) 5);\n        error.put((byte) 0);\n        error.put(code);\n        error.put(message);\n        error.put((byte) 0);\n\n        \/\/ Create and send the error packet\n        DatagramPacket errorPacket = new DatagramPacket(error.array(), error.array().length, address, port);\n        try {\n            \/\/ \u670d\u52a1\u7aef\u53d1\u9001\u9519\u8bef\u6570\u636e\u62a5\n            serverSocket.send(errorPacket);\n        } catch (IOException e) {\n            System.out.println(&quot;Error sending error&quot;);\n            \/\/ \u9519\u8bef\u8fd4\u56de\n            return;\n        }\n        System.out.println(&quot;Server Error sent&quot; + errorMessage);\n    }\n\n    \/\/ Write a file sent from a client to the servers storage\n    private void get(String fileName, String mode) throws Exception {\n\n        \/\/ Acknowledge the write request \u53d1\u90010\u5757\u7684ACK\n        byte[] block = { 0, 0 };\n        sendAcknowledgement(block, CLIENT_PORT);\n        \/\/ Receive the file\n        output = receivePackets(fileName, mode);\n        \/\/ If the file was received successfully, attempt to write it to a file\n        if (output != null) {\n            writeFile(output, (fileName));\n        }\n    }\n\n    \/\/ Send an acknowledgement \u53d1\u7ed9\u5ba2\u6237\u7aef\n    private void sendAcknowledgement(byte[] blockNumber, int portNumber) {\n\n        \/\/ Create the ack packet\n\n        \/**\n         * 04 00 ----------------------- | Opcode | Block | ----------------------- 2\n         * bytes 2 bytes\n         *\n         *\/\n\n        byte[] ackBytes = { (byte) 0, ACK, blockNumber[0], blockNumber[1] };\n        DatagramPacket ackPacket = new DatagramPacket(ackBytes, ackBytes.length, IPAddress, CLIENT_PORT);\n\n        try {\n            serverSocket.send(ackPacket);\n        } catch (IOException e) {\n            sendError(0, &quot;Error sending ack&quot;, IPAddress, CLIENT_PORT);\n        }\n    }\n\n    \/\/ Receive the file packets sent from a client\n    private ByteArrayOutputStream receivePackets(String fileName, String mode) throws IOException {\n\n        \/\/ File IO variables\n        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();\n        \/\/ 0\u5df2\u7ecf\u6536\u5230\u4e86 \u53d1\u7b2c1\u5757\n        int block = 1;\n        boolean packetsRemaining      = true;\n        byte[] packetByteBuffer;\n        DatagramPacket receivedPacket;\n\n        \/\/ If there are packets to come, continue receiving\n        while (packetsRemaining) {\n\n            \/\/ Determine if there is sufficient diskspace, otherwise raise an error\n            if (outputFileDir.getTotalSpace() &lt; 516) {\n                sendError(3, ERROR_3, IPAddress, CLIENT_PORT);\n                return null;\n            }\n            \/\/ Receive the new data packet 516B\n            packetByteBuffer = new byte[PACKET_SIZE];\n            receivedPacket = new DatagramPacket(packetByteBuffer, packetByteBuffer.length);\n\n            \/\/ Wait for a valid packet\n            while (true) {\n                try {\n                    \/\/ 5s timeout\n                    serverSocket.setSoTimeout(5000);\n                    serverSocket.receive(receivedPacket);\n                    if (receivedPacket.getPort() != CLIENT_PORT) {\n                        sendError(5, ERROR_5, receivedPacket.getAddress(), receivedPacket.getPort());\n                    } else {\n                        break;\n                    }\n                    \/\/ Resend the ack if the socket times out\n                } catch (SocketTimeoutException e) {\n                    \/\/ \u91cd\u53d1\u4e0a\u4e00\u5757\u7684ack \u9ad8\u51e0\u4f4d \u4f4e\u51e0\u4f4d\n                    byte blockMSB = (byte) (((block - 1) &gt;&gt;&gt; 8) &amp; 0xFF);\n                    byte blockLSB = (byte) (((block - 1)) &amp; 0xFF);\n                    byte[] blockA = { blockMSB, blockLSB };\n                    sendAcknowledgement(blockA, CLIENT_PORT);\n                }\n            }\n\n            \/\/ Buffer the received data \u65b0\u5f97\u5230\u7684\u5305\u7684\u5b57\u8282\u6570\u7ec4\n            ByteBuffer receiveBuffer = ByteBuffer.allocate(receivedPacket.getLength());\n            receiveBuffer.put(packetByteBuffer, 0, receivedPacket.getLength());\n            byte[] receivedData = receiveBuffer.array();\n\n            \/\/ Format if required for netascii\n            if (mode.equals(&quot;netascii&quot;)) {\n                String temp = new String(receivedData);\n                receivedData = Charset.forName(&quot;US-ASCII&quot;).encode(temp).array();\n                temp = new String(receivedData);\n            }\n\n            \/\/ Determine data type\n            byte opCode = receivedData[1];\n\n            if (opCode == DATA) {\n\n                \/\/ Check if final packet\n                if (receivedPacket.getLength() &lt; 516) {\n                    packetsRemaining = false;\n                    \/\/ Check if the file exists\n                    File fileOut = new File(outputFileDir.getAbsoluteFile() + &quot;\\\\&quot; + fileName);\n                    if (fileOut.exists()) {\n                        sendError(6, ERROR_6, IPAddress, CLIENT_PORT);\n                        return null;\n                    }\n                }\n\n                \/\/ Get block Number\n                byte[] temp1 = { (receivedData[2]), receivedData[3] };\n                int number = (((receivedData[2] &amp; 0xFF) &lt;&lt; 8) + (receivedData[3] &amp; 0xFF)) &amp; 0xFFFF;\n\n                \/\/ BUffer file\n                DataOutputStream dataOut = new DataOutputStream(byteOutputStream);\n                \/\/ \u6570\u636e\u62a5\u76844-516\u4e3a\u6570\u636e\u90e8\u5206\uff0c\u5199\u5165\u8f93\u51fa\u6d41\uff0c\u5934\u90e8\u4e0d\u5199\n                dataOut.write(receivedData, 4, receivedData.length - 4);\n\n                \/\/ Send ACK and increment block count \u53d1\u9001\u5f53\u524d\u63a5\u53d7\u5b9d\u7684\u786e\u8ba4\u62a5\n                sendAcknowledgement(temp1, CLIENT_PORT);\n                block++;\n            }\n            \/\/ Handle error responses\n            else if (opCode == ERR) {\n                packetByteBuffer[1] = (byte) 0;\n                packetByteBuffer[3] = (byte) 0;\n                byte[] zeroByteArray = { 0 };\n                String zeroString = new String(zeroByteArray);\n                String errorMessage = new String(packetByteBuffer);\n                String[] splitMessage = errorMessage.split(zeroString);\n                System.out.println(&quot;Error : &quot; + splitMessage[4]);\n                return null;\n            } else {\n                sendError(0, &quot;Undefined error&quot;, IPAddress, CLIENT_PORT);\n                return null;\n            }\n        }\n\n        \/\/ Return byte output\n        return byteOutputStream;\n    }\n\n    \/\/ Writes a received file to the server storage\n    private void writeFile(ByteArrayOutputStream byteOutputStream, String fileName) {\n        try {\n\n            \/\/ Write if the file doesn&#039;t exist, otherwise raise an error\n            File fileOut = new File(outputFileDir.getAbsoluteFile() + &quot;\\\\&quot; + fileName);\n            if (fileOut.exists()) {\n                sendError(6, ERROR_6, IPAddress, CLIENT_PORT);\n                return;\n            }\n            \/\/ Write the file\n            OutputStream outputStream = new FileOutputStream(fileOut);\n            byteOutputStream.writeTo(outputStream);\n\n            \/\/ Close the output streams\n            byteOutputStream.close();\n            outputStream.close();\n        }\n        \/\/ Handle file errors\n        catch (FileAlreadyExistsException e) {\n            sendError(6, ERROR_6, IPAddress, CLIENT_PORT);\n            return;\n        } catch (IOException e) {\n            sendError(6, ERROR_6, IPAddress, CLIENT_PORT);\n            return;\n        }\n    }\n\n}<\/code><\/pre>\n<h4>\u7a0b\u5e8f\u6539\u8fdb<\/h4>\n<p>\u6570\u636e\u5305\u4e3a512\u6574\u6570\u500d\u65f6\uff0c\u5728\u670d\u52a1\u5668\u63a5\u6536\u5230\u6700\u540e\u4e00\u5757\u6570\u636e\u5757\u540e\u53d1\u9001ACK\u540e\u5373\u5b8c\u6210\u4efb\u52a1\uff0c\u4f46\u82e5\u6b64\u65f6ACK\u4e22\u5305\uff0cCLIENT\u7aef\u4f1a\u4e00\u76f4\u8d85\u65f6\u7b49\u5f85\u91cd\u53d1\u6700\u540e\u4e00\u4e2a\u7a7a\u5305\uff0c\u53ea\u80fd\u8d70\u670d\u52a1\u7aef\u7684WRQ\/RRQ\u5224\u65ad\u7a7a\u5305\u4e3a\u975e\u6cd5\u64cd\u4f5c\u56de\u6267\u3002\u53e6\u53ef\u91c7\u7528\u591a\u7ebf\u7a0b\u6765\u6a21\u62df\u591a\u4e2a\u5ba2\u6237\u7aef\u540c\u65f6\u8bbf\u95ee\u670d\u52a1\u5668\u7684\u60c5\u51b5\uff0c\u4ee5\u68c0\u6d4b\u4f20\u8f93\u7684\u53ef\u9760\u6027\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TFTP\u534f\u8bae\u7b80\u4ecb TFTP\uff08Trivial File Transfer Protocol,\u7b80\u5355\u6587\u4ef6\u4f20\u8f93\u534f\u8bae\uff09\u662f &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/139.196.114.170\/?p=329\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">\u201cTFTP\u534f\u8bae\u5b9e\u73b0\u201d<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[67],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/posts\/329"}],"collection":[{"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/139.196.114.170\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=329"}],"version-history":[{"count":10,"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/posts\/329\/revisions"}],"predecessor-version":[{"id":2788,"href":"http:\/\/139.196.114.170\/index.php?rest_route=\/wp\/v2\/posts\/329\/revisions\/2788"}],"wp:attachment":[{"href":"http:\/\/139.196.114.170\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/139.196.114.170\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=329"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/139.196.114.170\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}