SocketSwitch was not used.
IMessageWriter + IMessageWriterFactory are not necessary, as messages are just buffers that need to be drained to the socket. Instead we have a standard MessageWriter that does that.
This commit is contained in:
parent
4bb99c6c38
commit
976ecb6af2
@ -1,23 +0,0 @@
|
||||
package com.jenkov.nioserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Selector;
|
||||
|
||||
/**
|
||||
* Created by jjenkov on 16-10-2015.
|
||||
*/
|
||||
public interface IMessageWriter {
|
||||
|
||||
/**
|
||||
* Called by IMessageProcessor - so no access to write Selector from here.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void enqueue(Message message);
|
||||
|
||||
public void write(Socket socket, ByteBuffer byteBuffer) throws IOException;
|
||||
|
||||
public boolean isEmpty();
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package com.jenkov.nioserver;
|
||||
|
||||
import java.nio.channels.Selector;
|
||||
|
||||
/**
|
||||
* Created by jjenkov on 16-10-2015.
|
||||
*/
|
||||
public interface IMessageWriterFactory {
|
||||
|
||||
public IMessageWriter createMessageWriter();
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import java.util.List;
|
||||
/**
|
||||
* Created by jjenkov on 21-10-2015.
|
||||
*/
|
||||
public class MessageWriter implements IMessageWriter {
|
||||
public class MessageWriter {
|
||||
|
||||
private List<Message> writeQueue = new ArrayList<>();
|
||||
private Message messageInProgress = null;
|
||||
@ -17,25 +17,15 @@ public class MessageWriter implements IMessageWriter {
|
||||
public MessageWriter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enqueue(Message message) {
|
||||
if(this.messageInProgress == null){
|
||||
this.messageInProgress = message;
|
||||
System.out.println("Message set as message in progress.");
|
||||
} else {
|
||||
this.writeQueue.add(message);
|
||||
System.out.println("Message enqueued.");
|
||||
}
|
||||
|
||||
//todo register socket for write interest
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(Socket socket, ByteBuffer byteBuffer) throws IOException {
|
||||
System.out.println("Writing message to socket");
|
||||
|
||||
byteBuffer.put(this.messageInProgress.sharedArray, this.messageInProgress.offset + this.bytesWritten, this.messageInProgress.length - this.bytesWritten);
|
||||
byteBuffer.flip();
|
||||
|
||||
@ -52,8 +42,8 @@ public class MessageWriter implements IMessageWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.writeQueue.isEmpty() && this.messageInProgress == null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,15 +12,16 @@ import java.util.*;
|
||||
*/
|
||||
public class ServerCore implements Runnable {
|
||||
|
||||
private MessageBuffer readMessageBuffer = null;
|
||||
private MessageBuffer writeMessageBuffer = null;
|
||||
private Queue<Socket> inboundSocketQueue = null;
|
||||
private Queue<Message> outboundMessageQueue = new LinkedList<>(); //todo use a better / faster queue.
|
||||
private Queue<Socket> inboundSocketQueue = null;
|
||||
|
||||
private Map<Long, Socket> socketMap = new HashMap<>();
|
||||
private MessageBuffer readMessageBuffer = null; //todo Not used now - but perhaps will be later - to check for space in the buffer before reading from sockets
|
||||
private MessageBuffer writeMessageBuffer = null; //todo Not used now - but perhaps will be later - to check for space in the buffer before reading from sockets (space for more to write?)
|
||||
|
||||
private IMessageReaderFactory messageReaderFactory = null;
|
||||
private IMessageWriterFactory messageWriterFactory = null;
|
||||
|
||||
private Queue<Message> outboundMessageQueue = new LinkedList<>(); //todo use a better / faster queue.
|
||||
|
||||
private Map<Long, Socket> socketMap = new HashMap<>();
|
||||
|
||||
private ByteBuffer readByteBuffer = ByteBuffer.allocate(1024 * 1024);
|
||||
private ByteBuffer writeByteBuffer = ByteBuffer.allocate(1024 * 1024);
|
||||
@ -36,7 +37,7 @@ public class ServerCore implements Runnable {
|
||||
private Set<Socket> nonEmptyToEmptySockets = new HashSet<>();
|
||||
|
||||
|
||||
public ServerCore(Queue<Socket> inboundSocketQueue, MessageBuffer readMessageBuffer, MessageBuffer writeMessageBuffer, IMessageReaderFactory messageReaderFactory, IMessageWriterFactory messageWriterFactory, IMessageProcessor messageProcessor) throws IOException {
|
||||
public ServerCore(Queue<Socket> inboundSocketQueue, MessageBuffer readMessageBuffer, MessageBuffer writeMessageBuffer, IMessageReaderFactory messageReaderFactory, IMessageProcessor messageProcessor) throws IOException {
|
||||
this.inboundSocketQueue = inboundSocketQueue;
|
||||
|
||||
this.readMessageBuffer = readMessageBuffer;
|
||||
@ -44,7 +45,6 @@ public class ServerCore implements Runnable {
|
||||
this.writeProxy = new WriteProxy(writeMessageBuffer, this.outboundMessageQueue);
|
||||
|
||||
this.messageReaderFactory = messageReaderFactory;
|
||||
this.messageWriterFactory = messageWriterFactory;
|
||||
|
||||
this.messageProcessor = messageProcessor;
|
||||
|
||||
@ -84,7 +84,7 @@ public class ServerCore implements Runnable {
|
||||
newSocket.socketChannel.configureBlocking(false);
|
||||
|
||||
newSocket.messageReader = this.messageReaderFactory.createMessageReader();
|
||||
newSocket.messageWriter = this.messageWriterFactory.createMessageWriter();
|
||||
newSocket.messageWriter = new MessageWriter();
|
||||
|
||||
this.socketMap.put(newSocket.socketId, newSocket);
|
||||
|
||||
@ -128,6 +128,7 @@ public class ServerCore implements Runnable {
|
||||
}
|
||||
|
||||
if(socket.endOfStreamReached){
|
||||
System.out.println("Socket closed: " + socket.socketId);
|
||||
this.socketMap.remove(socket.socketId);
|
||||
key.attach(null);
|
||||
key.cancel();
|
||||
@ -147,9 +148,7 @@ public class ServerCore implements Runnable {
|
||||
// Register all sockets that *have* data and which are not yet registered.
|
||||
registerNonEmptySockets();
|
||||
|
||||
|
||||
// Select from the Selector.
|
||||
|
||||
int writeReady = this.writeSelector.selectNow();
|
||||
|
||||
if(writeReady > 0){
|
||||
@ -185,6 +184,7 @@ public class ServerCore implements Runnable {
|
||||
private void cancelEmptySockets() {
|
||||
for(Socket socket : nonEmptyToEmptySockets){
|
||||
SelectionKey key = socket.socketChannel.keyFor(this.writeSelector);
|
||||
|
||||
key.cancel();
|
||||
}
|
||||
nonEmptyToEmptySockets.clear();
|
||||
@ -196,7 +196,7 @@ public class ServerCore implements Runnable {
|
||||
Socket socket = this.socketMap.get(outMessage.socketId);
|
||||
|
||||
if(socket != null){
|
||||
IMessageWriter messageWriter = socket.messageWriter;
|
||||
MessageWriter messageWriter = socket.messageWriter;
|
||||
if(messageWriter.isEmpty()){
|
||||
messageWriter.enqueue(outMessage);
|
||||
nonEmptyToEmptySockets.remove(socket);
|
||||
|
@ -11,9 +11,9 @@ public class Socket {
|
||||
|
||||
public long socketId;
|
||||
|
||||
public SocketChannel socketChannel = null;
|
||||
public SocketChannel socketChannel = null;
|
||||
public IMessageReader messageReader = null;
|
||||
public IMessageWriter messageWriter = null;
|
||||
public MessageWriter messageWriter = null;
|
||||
|
||||
public boolean endOfStreamReached = false;
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
package com.jenkov.nioserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Todo - rename class to SocketWriter ?
|
||||
*
|
||||
* Created by jjenkov on 20-10-2015.
|
||||
*/
|
||||
public class SocketSwitch {
|
||||
|
||||
private Map<Long, Socket> socketMap = new HashMap<>();
|
||||
private Map<Long, IMessageWriter> messageWriterMap = new HashMap<>();
|
||||
|
||||
private Set<Socket> socketsToCancel = new HashSet<>();
|
||||
private Set<Socket> socketsToRegister = new HashSet<>();
|
||||
|
||||
|
||||
public Set<Socket> getSocketsToCancel() {
|
||||
return this.socketsToCancel;
|
||||
}
|
||||
|
||||
public Set<Socket> getSocketsToRegister() {
|
||||
return this.socketsToRegister;
|
||||
}
|
||||
|
||||
//todo change putMessageWriter to registerSocket();
|
||||
public void registerSocket(Socket socket){
|
||||
System.out.println("Registering socket: " + socket.socketId );
|
||||
this.socketMap.put(socket.socketId, socket);
|
||||
this.messageWriterMap.put(socket.socketId, socket.messageWriter);
|
||||
}
|
||||
|
||||
public void enqueueMessage(long socketId, Message message){
|
||||
IMessageWriter messageWriter = this.messageWriterMap.get(socketId);
|
||||
|
||||
|
||||
|
||||
if(messageWriter != null){
|
||||
boolean wasEmpty = messageWriter.isEmpty();
|
||||
messageWriter.enqueue(message);
|
||||
|
||||
if(wasEmpty){
|
||||
Socket socket = this.socketMap.get(socketId);
|
||||
|
||||
if(this.socketsToCancel.contains(socket)){
|
||||
//Socket already registered with Selector. Remove cancellation request but
|
||||
// do not re-register socket with Selector
|
||||
this.socketsToCancel.remove(socket);
|
||||
} else {
|
||||
//Socket not currently registered with Selector. Request registration.
|
||||
this.socketsToRegister.add(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToSocket(Socket socket, ByteBuffer writeByteBuffer) throws IOException {
|
||||
IMessageWriter messageWriter = messageWriterMap.get(socket.socketId);
|
||||
if(messageWriter != null){
|
||||
messageWriter.write(socket, writeByteBuffer);
|
||||
|
||||
if(messageWriter.isEmpty()) {
|
||||
this.socketsToCancel.add(socket);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void unregisterSocket(long socketId){
|
||||
System.out.println("Unregistering socket: " + socketId);
|
||||
this.socketMap.remove(socketId);
|
||||
|
||||
//todo in case the message writer should survive a "missing connection" - don't remove it.
|
||||
this.messageWriterMap.remove(socketId);
|
||||
}
|
||||
|
||||
public void removeMessageWriter(long id){
|
||||
this.socketMap.remove(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -2,7 +2,6 @@ package com.jenkov.nioserver.example;
|
||||
|
||||
import com.jenkov.nioserver.*;
|
||||
import com.jenkov.nioserver.http.HttpMessageReaderFactory;
|
||||
import com.jenkov.nioserver.http.HttpMessageWriterFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
@ -14,7 +13,6 @@ import java.util.concurrent.BlockingQueue;
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
BlockingQueue inboundSocketQueue = new ArrayBlockingQueue(1024);
|
||||
|
||||
Server server = new Server(9999, inboundSocketQueue);
|
||||
@ -22,11 +20,9 @@ public class Main {
|
||||
Thread serverThread = new Thread(server);
|
||||
serverThread.start();
|
||||
|
||||
|
||||
MessageBuffer readMessageBuffer = new MessageBuffer();
|
||||
MessageBuffer writeMessageBuffer = new MessageBuffer();
|
||||
IMessageReaderFactory messageReaderFactory = new HttpMessageReaderFactory(readMessageBuffer);
|
||||
IMessageWriterFactory messageWriterFactory = new HttpMessageWriterFactory();
|
||||
|
||||
String httpResponse = "HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 38\r\n" +
|
||||
@ -46,7 +42,7 @@ public class Main {
|
||||
writeProxy.enqueue(response);
|
||||
};
|
||||
|
||||
ServerCore serverCore = new ServerCore(inboundSocketQueue, readMessageBuffer, writeMessageBuffer, messageReaderFactory, messageWriterFactory, messageProcessor);
|
||||
ServerCore serverCore = new ServerCore(inboundSocketQueue, readMessageBuffer, writeMessageBuffer, messageReaderFactory, messageProcessor);
|
||||
Thread serverCoreThread = new Thread(serverCore);
|
||||
serverCoreThread.start();
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
package com.jenkov.nioserver.http;
|
||||
|
||||
import com.jenkov.nioserver.IMessageWriter;
|
||||
import com.jenkov.nioserver.Message;
|
||||
import com.jenkov.nioserver.SocketSwitch;
|
||||
import com.jenkov.nioserver.Socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by jjenkov on 21-10-2015.
|
||||
*/
|
||||
public class HttpMessageWriter implements IMessageWriter {
|
||||
|
||||
private List<Message> writeQueue = new ArrayList<>();
|
||||
private Message messageInProgress = null;
|
||||
private int bytesWritten = 0;
|
||||
|
||||
public HttpMessageWriter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enqueue(Message message) {
|
||||
if(this.messageInProgress == null){
|
||||
this.messageInProgress = message;
|
||||
System.out.println("Message set as message in progress.");
|
||||
} else {
|
||||
this.writeQueue.add(message);
|
||||
System.out.println("Message enqueued.");
|
||||
}
|
||||
|
||||
//todo register socket for write interest
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(Socket socket, ByteBuffer byteBuffer) throws IOException {
|
||||
System.out.println("Writing message to socket");
|
||||
|
||||
byteBuffer.put(this.messageInProgress.sharedArray, this.messageInProgress.offset + this.bytesWritten, this.messageInProgress.length - this.bytesWritten);
|
||||
byteBuffer.flip();
|
||||
|
||||
this.bytesWritten += socket.write(byteBuffer);
|
||||
byteBuffer.clear();
|
||||
|
||||
if(bytesWritten >= this.messageInProgress.length){
|
||||
if(this.writeQueue.size() > 0){
|
||||
this.messageInProgress = this.writeQueue.remove(0);
|
||||
} else {
|
||||
this.messageInProgress = null;
|
||||
//todo unregister from selector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.writeQueue.isEmpty() && this.messageInProgress == null;
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package com.jenkov.nioserver.http;
|
||||
|
||||
import com.jenkov.nioserver.IMessageWriter;
|
||||
import com.jenkov.nioserver.IMessageWriterFactory;
|
||||
|
||||
import java.nio.channels.Selector;
|
||||
|
||||
/**
|
||||
* Created by jjenkov on 19-10-2015.
|
||||
*/
|
||||
public class HttpMessageWriterFactory implements IMessageWriterFactory {
|
||||
|
||||
@Override
|
||||
public IMessageWriter createMessageWriter() {
|
||||
return new HttpMessageWriter();
|
||||
//return null;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user