Commit 2d789c1c authored by Dr. Daniel Diaz Sánchez's avatar Dr. Daniel Diaz Sánchez
Browse files

Initial commit

parents
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>JavaNIOSocketExampleServer</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
package es.uc3m.it.aptel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import es.uc3m.it.aptel.connection.State;
import es.uc3m.it.aptel.messages.Message;
public class Server {
Selector selector = null;
ServerSocketChannel ss;
Logger logger = Logger.getLogger(Server.class.getCanonicalName());
public static void main(String args[])
{
try {
Server srv = new Server(8888);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Server(int port) throws IOException {
ss = ServerSocketChannel.open();
SocketAddress sa = new InetSocketAddress(port);
ss.bind(sa, 10);
selector = Selector.open();
// set passive socket non blocking
ss.configureBlocking(false);
ss.register(selector, SelectionKey.OP_ACCEPT);
logger.log(Level.INFO, "Listening at " + port);
// move to server blk
ServerSelector();
}
public void ServerSelector() throws IOException {
ss.configureBlocking(false);
while (true) {
try {
int readyChannels;
readyChannels = selector.select();
if (readyChannels == 0) {
logger.info("No channels (sockets) selected");
continue;
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey currentKey = keyIterator.next();
// we already get the key in currentKey, remove it from iterator
keyIterator.remove();
if (currentKey.isAcceptable()) {
logger.info("A new connection arrives");
// get the socket that has an incoming connection
// (passive)
ServerSocketChannel ssChannel = (ServerSocketChannel) currentKey.channel();
// accept the connection and log it
SocketChannel activeSocket = ssChannel.accept();
InetSocketAddress saddrs = (InetSocketAddress) activeSocket.getRemoteAddress();
logger.info("Client from " + saddrs.getAddress().getHostAddress() + " : " + saddrs.getPort()
+ " - is now connected");
// create a new Connection class to store the connection
// state
State state = new State(activeSocket);
// the active socket should be controlled with the
// selector
// an active socket can read and write
// we will register the active socket with the selector
// and use state as attachment
activeSocket.configureBlocking(false);
activeSocket.register(selector, SelectionKey.OP_READ, state);
} else if (currentKey.isConnectable()) {
logger.info("connectable...");
} else if (currentKey.isReadable()) {
logger.info("A new I/O operation on an active socket");
// get the socket that has an incoming connection
// (active)
SocketChannel activeSocket = (SocketChannel) currentKey.channel();
// check if the socket is closed
if (!currentKey.isValid()) {
if (!activeSocket.isConnected()) {
// close the socket
currentKey.cancel();
activeSocket.close();
break;
}
}
// get attachment
State state = (State) currentKey.attachment();
// read data
synchronized (state.getIn()) {
int numBytesRead;
while ((numBytesRead = activeSocket.read(state.getIn())) != 0) {
if (numBytesRead == -1)
throw new ClosedChannelException();
logger.info("loop reading " + numBytesRead + " from socket");
}
logger.info("Total bytes read " + state.getIn().position());
processMessage(state);
// prepare buffer for next message
state.getIn().clear();
}
} else {
logger.severe("Unexpected key");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public int writeMessage(State state, Message outgoing) {
int count = 0;
synchronized (state.getOut()) {
try {
// clean the outgoing buffer
state.getOut().clear();
outgoing.serialize(state.getOut());
// prepare buffer for reading to copu to socket
state.getOut().flip();
while (state.getOut().hasRemaining()) {
count += state.getSocket().write(state.getOut());
}
logger.info("sending " + count + " bytes through the socket");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return count;
}
private void processMessage(State state) {
// process message
// flip the incoming buffer
ByteBuffer in = state.getIn();
in.flip();
// get a message from the buffer
Message incoming = new Message(in);
String receivedText = incoming.getText();
logger.info("RCVD " + receivedText);
// this server transforms the text into CAPS and returns it
String newText = receivedText.toUpperCase();
Message outgoing = new Message(newText);
// send the response
writeMessage(state, outgoing);
}
}
package es.uc3m.it.aptel.connection;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class State {
ByteBuffer in = ByteBuffer.allocate(1024);
ByteBuffer out = ByteBuffer.allocate(1024);
SocketChannel activeSocket = null;
public State(SocketChannel activeSocket) {
this.activeSocket = activeSocket;
}
public ByteBuffer getIn() {
return in;
}
public void setIn(ByteBuffer in) {
this.in = in;
}
public ByteBuffer getOut() {
return out;
}
public void setOut(ByteBuffer out) {
this.out = out;
}
public SocketChannel getSocket() {
return activeSocket;
}
}
package es.uc3m.it.aptel.messages;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class Message {
String text = null;
public Message(String text) {
this.text = text;
}
public Message(ByteBuffer in)
{
deserialize(in);
}
public void serialize(ByteBuffer out)
{
// get the us-ascii representation of the text
byte[] data = text.getBytes(StandardCharsets.US_ASCII);
out.put(data);
}
public void deserialize(ByteBuffer in)
{
//read all as text (this is a very basic example)
int total = in.remaining();
byte[] data = new byte[total];
in.get(data);
// convert bytes into String (ascii enconding)
text = new String(data, StandardCharsets.US_ASCII);
// try in.getInt, in.getLong, in.getXXX for other types different from text
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment