簡體   English   中英

Java 使用 AsynchronousSocketChannel 將空字節 (\\x00) 作為 1 個字符發送

[英]Java send nullbyte (\x00) as 1 character using AsynchronousSocketChannel

我需要將 nullbyte 作為 1 個字符發送,此代碼將其作為 4 個字符發送,因此不是 nullbyte (\\x00) ,它不能作為純文本發送。 它正在發送到 Flash 客戶端。 我正在使用 AsynchronousSocketChannel 發送數據包。 nullbyte 是告訴服務器數據包已經結束。 例如,當我發送 test\\x00 時,它將它作為 test\\x00 發送,這是錯誤的。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;

import java.util.concurrent.Future;

public class Main {



    public static void main(String[] args) throws Exception {
        String connect = "gfdg";
        System.out.println(connect);

        String request = connect;
        AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
        SocketAddress serverAddr = new InetSocketAddress("artix.aqw.aq.com", 5588);
        Future<Void> result = channel.connect(serverAddr);
        result.get();
        Attachment attach = new Attachment();
        attach.channel = channel;
        attach.buffer = ByteBuffer.allocate(2048);
        attach.isRead = false;
        attach.mainThread = Thread.currentThread();

        Charset cs = Charset.forName("UTF-8");
        String msg = request;
        byte[] data = msg.getBytes(cs);
        attach.buffer.put(data);
        attach.buffer.flip();

        ReadWriteHandler readWriteHandler = new ReadWriteHandler();
        channel.write(attach.buffer, attach, readWriteHandler);
        attach.mainThread.join();
    }
}

class Attachment {
    AsynchronousSocketChannel channel;
    ByteBuffer buffer;
    Thread mainThread;
    boolean isRead;
}

class ReadWriteHandler implements CompletionHandler<Integer, Attachment> {

    @Override
    public void completed(Integer result, Attachment attach) {
        if (attach.isRead) {
            attach.buffer.flip();
            Charset cs = Charset.forName("UTF-8");
            int limits = attach.buffer.limit();
            byte bytes[] = new byte[limits];
            attach.buffer.get(bytes, 0, limits);
            String msg = new String(bytes, cs);
            String str = new String(bytes,cs).split("\0")[0];

            System.out.format("Server Responded: " + str + "\n");
            try {
                msg = this.getTextFromUser();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (msg.equalsIgnoreCase("bye")) {
                attach.mainThread.interrupt();
                return;
            }
            attach.buffer.clear();
            byte[] data = msg.getBytes(cs);
            attach.buffer.put(data);
            attach.buffer.flip();
            attach.isRead = false; // It is a write
            attach.channel.write(attach.buffer, attach, this);
        } else {
            attach.isRead = true;
            attach.buffer.clear();
            attach.channel.read(attach.buffer, attach, this);
        }
    }

    @Override
    public void failed(Throwable e, Attachment attach) {
        e.printStackTrace();
    }

    private String getTextFromUser() throws Exception {
        System.out.println("Please enter a  message:");
        BufferedReader consoleReader = new BufferedReader(
                new InputStreamReader(System.in));

        String msg = consoleReader.readLine() + "\\x00";
        return msg;
    }


}

在將字符串寫入通道后,您應該寫入一個空字節 ( 0x00 )。 您所做的不是它:您要附加字符串\\x00 (反斜杠后跟一個 x 和兩個 0)。

與我的第一直覺相反,如果您將 unicode 字符\附加到您的字符串中,它似乎會起作用,但最佳方法是在放入字符串后將值為0byte放入ByteBuffer

需要明確的是,我希望在附加\字節會加倍,因為 Java 將字符編碼為 UTF-16,因此為 2 個字節。 但是我們明確地將字符串編碼為 UTF-8 以將其作為字節獲取,因此空字符確實被編碼為單個空字節。

這是一個小演示,顯示了每個方法寫入通道的數據長度,然后它的值為字節:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Buffer {
    
    public static void main(String[] args) throws IOException {

        try (Scanner scan = new Scanner(System.in)) {

            boolean done = false;
            while(!done) {

                System.out.println("Enter string to encode, 'bye' to exit:");

                String s = scan.nextLine();
                if ("bye".equals(s.toLowerCase())) {
                    done = true;
                    break;
                }

                System.out.println("withNullChar");
                String withNullChar = s + '\u0000';
                ByteBuffer buff = ByteBuffer.allocate(1024);
                buff.put(withNullChar.getBytes(StandardCharsets.UTF_8));
                System.out.println("Length: " + buff.position());
                buff.flip();
                byte[] result = readBack(buff);
                printArray(result);

                System.out.println("withNullCharFaulty");
                String withNullCharFaulty = s + "\\x00";
                buff = ByteBuffer.allocate(1024);
                buff.put(withNullCharFaulty.getBytes(StandardCharsets.UTF_8));
                System.out.println("Length: " + buff.position());
                buff.flip();
                result = readBack(buff);
                printArray(result);

                System.out.println("with null byte");
                buff = ByteBuffer.allocate(1024);
                buff.put(s.getBytes(StandardCharsets.UTF_8)).put((byte) 0);
                System.out.println("Length: " + buff.position());
                buff.flip();
                result = readBack(buff);
                printArray(result);

            }

        }

    }

    public static byte[] readBack(ByteBuffer buff) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            try (WritableByteChannel channel = Channels.newChannel(bos)) {
                channel.write(buff);
                return bos.toByteArray();
            }
        }
    }

    public static void printArray(byte[] arr) {
        StringBuilder sb = new StringBuilder();
        for (byte b : arr)
            sb.append(String.format("%02X ", b));
        System.out.println(sb);
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM