[英]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 字符
\
附加到您的字符串中,它似乎会起作用,但最佳方法是在放入字符串后将值为0
的byte
放入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.