친구들! 저는 Java NIO에 익숙하지 않고 현재 비 차단 채팅 앱을 만들고자합니다. 클라이언트는 문제없이 서버에 연결합니다. 클라이언트는 서버에 메시지 또는 몇 개의 메시지를 쓰지 만 서버는 소켓 연결이 클라이언트 코드에서 종료 될 때만 메시지 읽기를 시작하므로 모든 메시지에 대해 클라이언트 코드에서 SocketChannel (또는 Socket 만)을 만들어 닫아야합니다. -이게 나에게 맞는 것 같지 않아. 나는 간단한 Java I/O와 NIO Selector로 클라이언트 측을 시도했다. 같은 문제 - SocketChannel 또는 Socket이 클라이언트에서 닫힌 경우에만 서버가 읽기 시작합니다. 누군가는 저에게 비 연결 연결을하기의 적당한 방법을 이야기하거나 저에게 나의 논리에있는 과실을 보여 주실 수 있습니까? 고맙습니다!Java NIO 서버/클라이언트 채팅 앱 - 소켓을 닫음으로써 데이터를 전송하는 것
public class NIOServer implements Runnable {
@Override
public void run() {
try {
runServer();
} catch (IOException e) {
e.printStackTrace();
}
}
private void runServer() throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(8080));
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
int readyChannels = selector.selectNow();
if(readyChannels==0){
continue;
}
System.out.println("Ready channels: "+readyChannels);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if(key.isAcceptable()){
ServerSocketChannel acceptableServer = (ServerSocketChannel)key.channel();
SocketChannel client = server.accept();
if(client!=null){
System.out.println("Client accepted!");
client.configureBlocking(false);
SelectionKey selectionKey = client.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}
}
if (key.isReadable()) {
read(key);
}
/*if(key.isConnectable()){
System.out.println("connectable");
}
if(key.isWritable()){
//System.out.println("writable");
}*/
}
}
}
public void read(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.clear();
int bytesRead = channel.read(buffer);
while(bytesRead>0){
System.out.println("Read bytes: "+ bytesRead);
bytesRead=channel.read(buffer);
if(bytesRead==-1){
channel.close();
key.cancel();
}
buffer.flip();
while(buffer.hasRemaining()){
System.out.print((char)buffer.get());
}
}
//key.cancel();
//channel.close();
}
}
클라이언트 NIO Selector가 :
이
서버 코드public class NIOSelectorClient implements Runnable{
private Selector selector;
@Override
public void run() {
try {
startClient();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startClient() throws IOException {
SocketChannel socketChannel= openConnection();
selector = Selector.open();
socketChannel.register(selector,SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
while(!Thread.interrupted()) {
int readyChannels = selector.selectNow();
if(readyChannels==0) {
continue;
}
Set<SelectionKey> keySet = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keySet.iterator();
while(keyIterator.hasNext()) {
SelectionKey currentKey = keyIterator.next();
keyIterator.remove();
if(!currentKey.isValid()) {
continue;
}
if(currentKey.isConnectable()) {
System.out.println("I'm connected to the server!");
handleConnectable(currentKey);
}
if(currentKey.isWritable()){
handleWritable(currentKey);
}
}
}
}
private void handleWritable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100);
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message to server: ");
String output = scanner.nextLine();
buffer.put(output.getBytes());
buffer.flip();
//while(buffer.hasRemaining()) {
channel.write(buffer);
//}
System.out.println("Message send");
buffer.clear();
channel.close();
key.cancel();
}
private void handleConnectable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if(channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
}
private static SocketChannel openConnection() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
socketChannel.configureBlocking(false);
while(!socketChannel.finishConnect()) {
System.out.println("waiting connection....");
}
return socketChannel;
}
}
그리고 이것은 비 NIO cliet입니다 :
public class NIOClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8080);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(socket.isConnected()) {
//synchronized (socket) {
writeMessage(socket,writer);
//readServerMessage(socket);
//}
}
}
public static void writeMessage(Socket socket, BufferedWriter writer) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message: ");
String output = "Client 1: " + scanner.nextLine();
writer.write(output);
writer.flush();
//writer.close();
}
public static void readServerMessage(Socket socket) throws IOException {
}
}
TCP_NODELAY를 활성화 해보십시오 :'socketChannel.setOption (StandardSocketOptions.TCP_NODELAY, true);' 이렇게하면 TCP가 쓰기 버퍼에 데이터를 사용할 수있는 즉시 전송하게됩니다. – Malt
댓글을 주셔서 감사합니다! 나는이 옵션을 true로 설정하려고 시도했지만 여전히 같은 방식으로 작동한다. 간단한 IO 소켓에서는 이것을 시도했지만 NIO SocketChannel에서는 다른 아이디어가 있는가? :) – bulibas