我正在练习NIO并尝试使用客户端和服务器端制作一个简单的应用程序。这个应用程序应该只是从clien发送到服务器的消息,并获取其他消息作为响应。我的代码在这里。但是我有很多不同的问题。
有时来自方法int bytesRead = socketChannel.read(byteBuffer);
的行bytesRead = socketChannel.read(byteBuffer);
或readMessage()
会读取无限的零字节序列并抛出OOM错误。
有时来自服务器的响应看起来像that而不是{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}
。
有时响应有这样奇怪的尾巴:{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}YQ11ZVwA\u003d
server和cliend都使用相同的方法进行读写。
我从客户{"class":"server.PasswordHashRequest","login":"admin"}
发送并期待{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}
。
使用相同的代码,我现在可以得到一个问题,几分钟后可以得到其他问题。
我尝试过任何我认识的事情。我是否设法在Java中获得了段错误?
客户端代码:
@Test
public void main() throws Exception {
System.out.println("Opening socket");
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9090);
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
Selector selector = Selector.open();
socketChannel.register(selector, OP_CONNECT);
socketChannel.connect(socketAddress);
PasswordHashRequest request = new PasswordHashRequest("admin");
System.out.println("Socket open");
while (true) {
System.out.println("Client selector awoken");
selector.select();
for (SelectionKey selectionKey : selector.selectedKeys()) {
if (selectionKey.isConnectable()) {
socketChannel.finishConnect();
selectionKey.interestOps(OP_WRITE);
} else if (selectionKey.isReadable()) {
String response = ServerManager.readMessage((SocketChannel) selectionKey.channel());
System.out.println(response);
server.interrupt();
} else if (selectionKey.isWritable()) {
ServerManager.sendMessage(request, (SocketChannel) selectionKey.channel());
System.out.println("Request sent");
selectionKey.interestOps(OP_READ);
}
}
}
}
服务器端代码:
public void run() {
System.out.println("Main thread started");
while (true) {
try {
// Get ready channels
int readyChannels = selector.select();
if (readyChannels == 0) { continue; }
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
// Handle Events
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
// New Client
if (key.isAcceptable()) {
System.out.println("New Client Accepted");
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
serverSocketChannel.configureBlocking(false);
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
SelectionKey clientKey = socketChannel.register(selector, SelectionKey.OP_READ);
Random randomInt = new Random(System.currentTimeMillis());
clientKey.attach(randomInt.nextInt(Integer.SIZE - 1));
}
// Client has sent data
else if (key.isReadable()) {
handleInput(key);
}
keyIterator.remove();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
阅读方法:
public static String readMessage(SocketChannel socketChannel) throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
byteBuffer.clear();
StringBuilder stringBuilder = new StringBuilder();
int bytesRead = socketChannel.read(byteBuffer);
while (bytesRead != -1) {
byteBuffer.flip();
String byteString = new String(byteBuffer.array(), Charset.forName("UTF-8"));
stringBuilder.append(byteString);
byteBuffer.clear();
bytesRead = socketChannel.read(byteBuffer);
}
socketChannel.shutdownInput();
return stringBuilder.toString();
}
写方法:
public static void writeMessage(String message, SocketChannel channel) throws IOException {
message += "\r\n";
System.out.println(message);
int bufferLength = 16;
byte[] responseBytes = message.getBytes();
int offset = 0;
ByteBuffer buf = ByteBuffer.allocate(bufferLength);
while (responseBytes.length > offset) {
buf.clear();
int div = responseBytes.length - offset;
if (div >= bufferLength) {
buf.put(responseBytes, offset, bufferLength);
} else {
buf.put(responseBytes, offset, div);
}
buf.flip();
channel.write(buf);
offset += bufferLength;
}
channel.shutdownOutput();
}
答案 0 :(得分:2)
bytesRead <= 0
write()
返回零,你的写方法应该停止尝试写入,然后(并且只有那时)注册OP_WRITE的通道,并且只在它触发时继续写入。在这里看到许多类似的问题。