简体   繁体   English

Java 使用 AsynchronousSocketChannel 将空字节 (\\x00) 作为 1 个字符发送

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

I need to send nullbyte as 1 character this code send its as 4 characters so not a nullbyte (\\x00) , it can't be sending it as plain text.我需要将 nullbyte 作为 1 个字符发送,此代码将其作为 4 个字符发送,因此不是 nullbyte (\\x00) ,它不能作为纯文本发送。 it's sending to a flash client.它正在发送到 Flash 客户端。 I'm using AsynchronousSocketChannel to send the packets.我正在使用 AsynchronousSocketChannel 发送数据包。 the nullbyte is to tell the server that the packet has ended. nullbyte 是告诉服务器数据包已经结束。 for example when I send test\\x00 it sends it as test\\x00 which is wrong.例如,当我发送 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;
    }


}

You should write a single null byte ( 0x00 ) after writing your string to the channel.在将字符串写入通道后,您应该写入一个空字节 ( 0x00 )。 What you're doing is not it: you're appending the string \\x00 instead (a backslash followed by an x and two 0s).您所做的不是它:您要附加字符串\\x00 (反斜杠后跟一个 x 和两个 0)。

Against my first instincts, it seems it will work if you append the unicode character \ to your string, but the optimal way to do it is simply to put a byte with value 0 into the ByteBuffer after putting your string.与我的第一直觉相反,如果您将 unicode 字符\附加到您的字符串中,它似乎会起作用,但最佳方法是在放入字符串后将值为0byte放入ByteBuffer

To be clear, I expected the null byte to be doubled when you append \ , as Java encodes chars as UTF-16, hence on 2 bytes.需要明确的是,我希望在附加\字节会加倍,因为 Java 将字符编码为 UTF-16,因此为 2 个字节。 But we're explicitly encoding the String to UTF-8 to get it as bytes, so the null char is indeed encoded as a single null byte.但是我们明确地将字符串编码为 UTF-8 以将其作为字节获取,因此空字符确实被编码为单个空字节。

Here's a small demo of this, showing for each method the length of data written to the channel, then its value as bytes:这是一个小演示,显示了每个方法写入通道的数据长度,然后它的值为字节:

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