org.jgroups.blocks.cs.NioServer Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
package org.jgroups.blocks.cs;
import org.jgroups.Address;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.DefaultThreadFactory;
import org.jgroups.util.ThreadFactory;
import org.jgroups.util.Util;
import java.net.InetAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
/**
* Server for sending and receiving messages via NIO channels. Uses only a single thread to accept, connect, write and
* read connections. Read messages are passed to a receiver, which typically uses a thread pool to process messages.
* Note that writes can get dropped, e.g. in the case where we have a previous write pending and a new write is received.
* This is typically not an issue as JGroups retransmits messages, but might become one when using NioServer standalone,
* ie. outside of JGroups.
* @author Bela Ban
* @since 3.6.5
*/
public class NioServer extends NioBaseServer {
protected ServerSocketChannel channel; // used to accept connections from peers
/**
* Creates an instance of NioServer.
* @param bind_addr The local bind address and port. If null, a bind address and port will be picked by the OS.
*/
public NioServer(IpAddress bind_addr) throws Exception {
this(bind_addr != null? bind_addr.getIpAddress() : null, bind_addr != null? bind_addr.getPort() : 0);
}
/**
* Creates an instance of {@link NioServer} that opens a server channel and listens for connections.
* @param bind_addr The local address to bind to. If null, the address will be picked by the OS
* @param port The local port to bind to
* @return An instance of {@link NioServer}. Needs to be started next.
* @throws Exception Thrown if the creation failed
*/
public NioServer(InetAddress bind_addr, int port) throws Exception {
this(new DefaultThreadFactory("nio", false), bind_addr, port, port+50, null, 0);
}
/**
* Creates an instance of {@link NioServer} that opens a server channel and listens for connections.
* @param thread_factory The thread factory used to create new threads
* @param bind_addr The local address to bind to. If null, the address will be picked by the OS
* @param end_port If srv_port is taken, the next port is tried, until end_port has been reached, in which case an
* exception will be thrown. If srv_port == end_port, only 1 port will be tried.
* @param external_addr The external address in case of NAT. Ignored if null.
* @param external_port The external port on the NA. If 0, srv_port is used.
* @return An instance of {@link NioServer}. Needs to be started next.
* @throws Exception Thrown if the creation failed
*/
public NioServer(ThreadFactory thread_factory, IpAddress bind_addr, int end_port, IpAddress external_addr) throws Exception {
this(thread_factory, bind_addr != null? bind_addr.getIpAddress() : null,
bind_addr != null? bind_addr.getPort() : 0, end_port,
external_addr != null? external_addr.getIpAddress() : null, external_addr != null? external_addr.getPort() : 0);
}
/**
* Creates an instance of {@link NioServer} that opens a server channel and listens for connections.
* @param thread_factory The thread factory used to create new threads
* @param bind_addr The local address to bind to. If null, the address will be picked by the OS
* @param srv_port The local port to bind to If 0, the port will be picked by the OS.
* @param end_port If srv_port is taken, the next port is tried, until end_port has been reached, in which case an
* exception will be thrown. If srv_port == end_port, only 1 port will be tried.
* @param external_addr The external address in case of NAT. Ignored if null.
* @param external_port The external port on the NA. If 0, srv_port is used.
* @return An instance of {@link NioServer}. Needs to be started next.
* @throws Exception Thrown if the creation failed
*/
public NioServer(ThreadFactory thread_factory, InetAddress bind_addr, int srv_port, int end_port,
InetAddress external_addr, int external_port) throws Exception {
super(thread_factory);
channel=Util.createServerSocketChannel(bind_addr, srv_port, end_port);
channel.configureBlocking(false);
selector=Selector.open();
acceptor=factory.newThread(new Acceptor(), "NioServer.Selector [" + channel.getLocalAddress() + "]");
channel.register(selector, SelectionKey.OP_ACCEPT, null);
local_addr=localAddress(bind_addr, channel.socket().getLocalPort(), external_addr, external_port);
}
protected NioServer(ThreadFactory f) {
super(f);
}
@Override
protected void handleAccept(SelectionKey key) throws Exception {
SocketChannel client_channel=channel.accept();
NioConnection conn=null;
if(client_channel == null) return; // can happen if no connection is available to accept
try {
conn=new NioConnection(client_channel, NioServer.this);
SelectionKey client_key=client_channel.register(selector, SelectionKey.OP_READ, conn);
conn.key(client_key); // we need to set the selection key of the client channel *not* the server channel
Address peer_addr=conn.peerAddress();
if(use_peer_connections)
return;
synchronized(this) {
replaceConnection(peer_addr, conn); // closes old conn
conn.start();
log.trace("%s: accepted connection from %s", local_addr, peer_addr);
}
}
catch(Throwable ex) {
Util.close(conn);
removeConnectionIfPresent(conn.peerAddress(), conn);
throw ex;
}
}
@Override
@ManagedOperation(description="Starts the server")
public synchronized void start() throws Exception {
if(running.compareAndSet(false, true)) {
acceptor.start();
super.start();
}
}
@Override
@ManagedOperation(description="Stops the server")
public synchronized void stop() {
super.stop();
if(running.compareAndSet(true, false))
Util.close(selector, channel); // closing the selector also stops the acceptor thread
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy