Java - 测试与 jUnit 的套接字通信
Java - Testing socket communication with jUnit
我正在测试一个 class,它使用 jUnit 4 处理基于套接字的通信。我的测试 class 启动一个模拟客户端的线程。
private class BeaconSimulator implements Runnable {
private String address = null;
private int port = 0;
BeaconSimulator(String address, int port) {
this.address = address;
this.port = port;
}
@Override
public void run() {
try (
Socket s = new Socket(address, port);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream()) {
IOUtils.write(DatatypeConverter.parseHexBinary(
"02000A00080001113E419F00D8000AB0ACB9AC309C22D84A11"), os);
ack = IOUtils.toByteArray(is);
} catch (UnknownHostException e) {
System.err.print(e);
} catch (IOException e) {
System.err.print(e);
}
}
}
我是这样启动的:
@Test
public void testBeaconCommunicationHandlerProcess() throws CustomException, InterruptedException, IOException {
CustomBean bean = new CustomBean();
ServerSocket server = new ServerSocket(8088);
Thread t = new Thread(new BeaconSimulator("localhost", 8088));
t.start();
bean.setSocket(server.accept());
new BeaconCommunicationHandler(bean).execute();
t.join();
assertArrayEquals(DatatypeConverter.parseHexBinary("0500000000"), ack);
server.close();
}
BeaconCommunicationHandler 对象的执行方法执行以下操作:
LOG.info("Communication with {} started", getRunnableBean().getSocket().getInetAddress());
try (
InputStream is = getRunnableBean().getSocket().getInputStream();
OutputStream os = getRunnableBean().getSocket().getOutputStream()) {
LOG.info("Reading MO on socket {}", getRunnableBean().getSocket().getInetAddress());
try {
message = IOUtils.toByteArray(is);
} catch (IOException e) {
throw new FunctionalGenException("Failed to read on socket", e);
}
}
LOG.debug("MO from {} -> {}", getRunnableBean().getSocket().getInetAddress(), Hex.encodeHexString(message).toUpperCase());
LOG.info("Ending communication with {}", getRunnableBean().getSocket().getInetAddress());
try (DataOutputStream dos = new DataOutputStream(os)) {
dos.write(DatatypeConverter.parseHexBinary("0500000000"));
} catch (IOException e) {
throw new FunctionalGenException("Failed to send the final packet", e);
}
问题是,当我不尝试在我的 BeaconSimulator 线程中读取时(通过删除行 ack = IOUtils.toByteArray(is)
),一切都运行到最后,但如果我尝试读取,测试块。
没有行 ack = IOUtils.toByteArray(is)
:
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 started
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Reading MO on socket /127.0.0.1
02-07-2020 14:23:57 DEBUG - main - BeaconCommunicationHandler - MO from /127.0.0.1 -> 02000A00080001113E419F00D8000AB0ACB9AC309C22D84A11
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Ending communication with /127.0.0.1
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 ended
用行 ack = IOUtils.toByteArray(is)
:
02-07-2020 13:51:07 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 started
02-07-2020 13:51:07 INFO - main - BeaconCommunicationHandler - Reading MO on socket /127.0.0.1
它卡在那里。
感谢您的帮助
从套接字读取数据
问题可能出在您创建 inputStream 的方式上,请执行以下操作:
final ServerSocket server = new ServerSocket(port);
final Socket socket = server.accept();
final DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
将 InputStream 包装在 DataInputStream 中允许您使用 readChar()、readInt() 或 readLine() 等专用方法以可移植的方式读取文本行、java 原语等。
如果问题是 InputStream 的位置
InputStream支持重置时
好像用了InputStream就行了
ack = IOUtils.toByteArray(is)
已被预先读取,让 Stream 位于其位置的末尾,因此无法从中获取字节数组。尝试执行以下操作,看看它是否能解决您的问题,并将其位置移动到流的开头:
is.reset();
ack = IOUtils.toByteArray(is);
我发现 对获得答案很有帮助。
当InputStream不支持重置时
如果不支持重置并且我们想多次查看相同的信息,我们可以将此数据从您的 InputStream
复制到 ByteArrayOutputStream
。
从 Java 9 开始,我们可以很快做到这一点
final ByteArrayOutputStream os = new ByteArrayOutputStream();
final is.transferTo(os);
final InputStream clonedIs = new ByteArrayInputStream(os.ToByteArray());
感谢 Damian229,我做了一些修补并找到了解决方案。 IOUtils 方法似乎无法正常工作。我用简单易用的“原生” OutputStream.write(byte[]) 方法替换了写入方法,并用以下内容替换了读取方法:
public byte[] readInputStream(InputStream is) throws IOException {
byte[] message = null;
byte[] buf = new byte[READ_SIZE];
int readSize = -1;
do {
readSize = is.read(buf);
if (readSize != -1) {
buf = Arrays.copyOfRange(buf, 0, readSize);
}
message = message == null ? buf.clone() : ArrayUtils.addAll(message, buf);
} while (readSize == READ_SIZE);
return message;
}
我做了这个方法,所以和IOUtils.read(InputStream)一样使用,现在通讯不卡了。
谢谢 Damian229 的宝贵时间!
我正在测试一个 class,它使用 jUnit 4 处理基于套接字的通信。我的测试 class 启动一个模拟客户端的线程。
private class BeaconSimulator implements Runnable {
private String address = null;
private int port = 0;
BeaconSimulator(String address, int port) {
this.address = address;
this.port = port;
}
@Override
public void run() {
try (
Socket s = new Socket(address, port);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream()) {
IOUtils.write(DatatypeConverter.parseHexBinary(
"02000A00080001113E419F00D8000AB0ACB9AC309C22D84A11"), os);
ack = IOUtils.toByteArray(is);
} catch (UnknownHostException e) {
System.err.print(e);
} catch (IOException e) {
System.err.print(e);
}
}
}
我是这样启动的:
@Test
public void testBeaconCommunicationHandlerProcess() throws CustomException, InterruptedException, IOException {
CustomBean bean = new CustomBean();
ServerSocket server = new ServerSocket(8088);
Thread t = new Thread(new BeaconSimulator("localhost", 8088));
t.start();
bean.setSocket(server.accept());
new BeaconCommunicationHandler(bean).execute();
t.join();
assertArrayEquals(DatatypeConverter.parseHexBinary("0500000000"), ack);
server.close();
}
BeaconCommunicationHandler 对象的执行方法执行以下操作:
LOG.info("Communication with {} started", getRunnableBean().getSocket().getInetAddress());
try (
InputStream is = getRunnableBean().getSocket().getInputStream();
OutputStream os = getRunnableBean().getSocket().getOutputStream()) {
LOG.info("Reading MO on socket {}", getRunnableBean().getSocket().getInetAddress());
try {
message = IOUtils.toByteArray(is);
} catch (IOException e) {
throw new FunctionalGenException("Failed to read on socket", e);
}
}
LOG.debug("MO from {} -> {}", getRunnableBean().getSocket().getInetAddress(), Hex.encodeHexString(message).toUpperCase());
LOG.info("Ending communication with {}", getRunnableBean().getSocket().getInetAddress());
try (DataOutputStream dos = new DataOutputStream(os)) {
dos.write(DatatypeConverter.parseHexBinary("0500000000"));
} catch (IOException e) {
throw new FunctionalGenException("Failed to send the final packet", e);
}
问题是,当我不尝试在我的 BeaconSimulator 线程中读取时(通过删除行 ack = IOUtils.toByteArray(is)
),一切都运行到最后,但如果我尝试读取,测试块。
没有行 ack = IOUtils.toByteArray(is)
:
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 started
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Reading MO on socket /127.0.0.1
02-07-2020 14:23:57 DEBUG - main - BeaconCommunicationHandler - MO from /127.0.0.1 -> 02000A00080001113E419F00D8000AB0ACB9AC309C22D84A11
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Ending communication with /127.0.0.1
02-07-2020 14:23:57 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 ended
用行 ack = IOUtils.toByteArray(is)
:
02-07-2020 13:51:07 INFO - main - BeaconCommunicationHandler - Communication with /127.0.0.1 started
02-07-2020 13:51:07 INFO - main - BeaconCommunicationHandler - Reading MO on socket /127.0.0.1
它卡在那里。
感谢您的帮助
从套接字读取数据
问题可能出在您创建 inputStream 的方式上,请执行以下操作:
final ServerSocket server = new ServerSocket(port);
final Socket socket = server.accept();
final DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
将 InputStream 包装在 DataInputStream 中允许您使用 readChar()、readInt() 或 readLine() 等专用方法以可移植的方式读取文本行、java 原语等。
如果问题是 InputStream 的位置
InputStream支持重置时
好像用了InputStream就行了
ack = IOUtils.toByteArray(is)
已被预先读取,让 Stream 位于其位置的末尾,因此无法从中获取字节数组。尝试执行以下操作,看看它是否能解决您的问题,并将其位置移动到流的开头:
is.reset();
ack = IOUtils.toByteArray(is);
我发现
当InputStream不支持重置时
如果不支持重置并且我们想多次查看相同的信息,我们可以将此数据从您的 InputStream
复制到 ByteArrayOutputStream
。
从 Java 9 开始,我们可以很快做到这一点
final ByteArrayOutputStream os = new ByteArrayOutputStream();
final is.transferTo(os);
final InputStream clonedIs = new ByteArrayInputStream(os.ToByteArray());
感谢 Damian229,我做了一些修补并找到了解决方案。 IOUtils 方法似乎无法正常工作。我用简单易用的“原生” OutputStream.write(byte[]) 方法替换了写入方法,并用以下内容替换了读取方法:
public byte[] readInputStream(InputStream is) throws IOException {
byte[] message = null;
byte[] buf = new byte[READ_SIZE];
int readSize = -1;
do {
readSize = is.read(buf);
if (readSize != -1) {
buf = Arrays.copyOfRange(buf, 0, readSize);
}
message = message == null ? buf.clone() : ArrayUtils.addAll(message, buf);
} while (readSize == READ_SIZE);
return message;
}
我做了这个方法,所以和IOUtils.read(InputStream)一样使用,现在通讯不卡了。 谢谢 Damian229 的宝贵时间!