package org.jgroups.tests.rt.transports; import org.jgroups.logging.Log; import org.jgroups.logging.LogFactory; import org.jgroups.tests.RoundTrip; import org.jgroups.tests.rt.RtReceiver; import org.jgroups.tests.rt.RtTransport; import org.jgroups.util.Util; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.List; /** * @author Bela Ban * @since 4.0 */ public class NioTransport implements RtTransport { protected ServerSocketChannel srv_channel; protected SocketChannel client_channel; protected Receiver receiver_thread; protected RtReceiver receiver; protected InetAddress host; protected int port=7800; protected boolean server, direct_buffers; // direct buffers protected final Log log=LogFactory.getLog(NioTransport.class); public NioTransport() { } public String[] options() { return new String[]{"-host <host>", "-port <port>", "-server", "-direct"}; } public void options(String... options) throws Exception { if(options == null) return; for(int i=0; i < options.length; i++) { if(options[i].equals("-server")) { server=true; continue; } if(options[i].equals("-host")) { host=InetAddress.getByName(options[++i]); continue; } if(options[i].equals("-port")) { port=Integer.parseInt(options[++i]); continue; } if(options[i].equals("-direct")) { direct_buffers=Boolean.valueOf(options[++i]); } } if(host == null) host=InetAddress.getLocalHost(); } public void receiver(RtReceiver receiver) { this.receiver=receiver; } public Object localAddress() {return null;} public List<? extends Object> clusterMembers() { return null; } public void start(String ... options) throws Exception { options(options); if(server) { // simple single threaded server, can only handle a single connection at a time srv_channel=ServerSocketChannel.open(); srv_channel.bind(new InetSocketAddress(host, port), 50); System.out.println("server started (ctrl-c to kill)"); for(;;) { client_channel=srv_channel.accept(); // client_channel.socket().setTcpNoDelay(true); // we're concerned about latency receiver_thread=new Receiver(); receiver_thread.start(); } } else { client_channel=SocketChannel.open(); //client_channel.socket().setTcpNoDelay(true); client_channel.connect(new InetSocketAddress(host, port)); receiver_thread=new Receiver(); receiver_thread.start(); } } public void stop() { Util.close(srv_channel, client_channel); } public void send(Object dest, byte[] buf, int offset, int length) throws Exception { ByteBuffer sbuf=ByteBuffer.wrap(buf, offset, length); client_channel.write(sbuf); } protected class Receiver extends Thread { public void run() { ByteBuffer buf=direct_buffers? ByteBuffer.allocateDirect(RoundTrip.PAYLOAD) : ByteBuffer.allocate(RoundTrip.PAYLOAD); for(;;) { try { buf.position(0); int num=client_channel.read(buf); if(num == -1) break; if(num != RoundTrip.PAYLOAD) throw new IllegalStateException("expected " + RoundTrip.PAYLOAD + " bytes, but got only " + num); if(receiver != null) { buf.flip(); int offset=buf.hasArray()? buf.arrayOffset() + buf.position() : buf.position(), len=buf.remaining(); if(!buf.isDirect()) receiver.receive(null, buf.array(), offset, len); else { // by default use a copy; but of course implementers of Receiver can override this byte[] tmp=new byte[len]; buf.get(tmp, 0, len); receiver.receive(null, tmp, 0, len); } } } catch(Exception e) { e.printStackTrace(); } } Util.close(client_channel); } } }