Interface NetworkService
-
- All Superinterfaces:
Service
@DefaultServiceFactory(NetworkServiceFactory.class) public interface NetworkService extends Service
« start hereEntry point to TCP-based client/server communication API.Overview
NetworkService
provides an abstraction layer on top of sockets API for building connection-oriented communication protocols.- Service Configuration
- Connectors
- Connectors Configuration
- Protocol Identifier
- SSL Encryption
- Data Serialization
- Thread Management
- Example
Service Configuration
NetworkService
can be configured and registered within theHekateBootstrap
via theNetworkServiceFactory
class as in the example below:// Prepare network service factory. NetworkServiceFactory factory = new NetworkServiceFactory() // Configure options. .withPort(10012) // Cluster node network port. .withPortRange(100) // ... if port is busy then auto-increment it .withNioThreads(10) // Number of threads to serve NIO operations .withConnectTimeout(5000) // Timeout of connecting to a remote peer .withHeartbeatInterval(500) // Heartbeat interval for each socket connection to keep alive .withHeartbeatLossThreshold(4); // Maximum amount of lost heartbeats // ... other options ... // Start node. Hekate hekate = new HekateBootstrap() .withService(factory) .join(); // Access the service. NetworkService network = hekate.network();
Note: This example requires Spring Framework integration (see HekateSpringBootstrap).<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.hekate.io/spring/hekate-core" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.hekate.io/spring/hekate-core http://www.hekate.io/spring/hekate-core.xsd"> <h:node id="hekate"> <!-- Network service. --> <h:network host="any-ip4" port="10012" port-range="100" nio-threads="10" heartbeat-interval-ms="500" heartbeat-loss-threshold="4" connect-timeout-ms="5000"> <!-- ...other options... --> </h:network> <!-- ...other services... --> </h:node> </beans>
Note: This example requires Spring Framework integration (see HekateSpringBootstrap).<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hekate" class="io.hekate.spring.bean.HekateSpringBootstrap"> <property name="services"> <list> <!-- Network service. --> <bean class="io.hekate.network.NetworkServiceFactory"> <property name="port" value="10012"/> <property name="portRange" value="100"/> <property name="nioThreads" value="10"/> <property name="heartbeatInterval" value="500"/> <property name="heartbeatLossThreshold" value="4"/> <property name="connectTimeout" value="5000"/> <!-- ...other options... --> </bean> <!-- ...other services... --> </list> </property> </bean> </beans>
Please see the documentation of
NetworkServiceFactory
class for more details about the available configuration options.Connectors
Communication units in the
NetworkService
are represented by theNetworkConnector
interface. This interface provides API for creating client connections based on the connector options as well as accepting connections from remote clients (optional).The client side of a connector API is represented by the
NetworkClient
interface. Each client manages a single socket connection and provides API for connecting to remote endpoints and sending/receiving messages to/from them. Instances if this interface can be be obtained fromNetworkConnector
as illustrated in the example below.The server side of a connector API is represented by the
NetworkServerHandler
interface. This interface provides callback methods that get notified upon various events of remote clients (connects, disconnects, new messages, etc). Instances of this interface can be registered viaNetworkConnectorConfig.setServerHandler(NetworkServerHandler)
method as illustrated in the example below.Note:
NetworkServerHandler
is optional and if not specified for particularNetworkConnector
then such connector will act in a pure client mode and will not be able to accept connections from remote addresses.Connectors Configuration
NetworkConnector
configuration is represented by theNetworkConnectorConfig
class. Please see its documentation for the complete list of all available configuration options.Instances of this class can be registered within the
NetworkService
viaNetworkServiceFactory.setConnectors(List)
method.Protocol Identifier
Each connector must have a protocol identifier. This identifier is used by the
NetworkService
to select whichNetworkConnector
should be responsible for processing each particular connection from a remoteNetworkClient
. WhenNetworkClient
established a new connection to a remoteNetworkService
it submits its protocol identifier as part of an initial handshake message. This identifier is used by the remoteNetworkService
to select aNetworkConnector
instance that is configured with exactly the same protocol identifier. If such instance can be found then all subsequent communication events will be handled by itsNetworkServerHandler
. If such instance can't be found then connection will be rejected.SSL Encryption
It is possible to configure
NetworkService
to use secure communications by settingSSL configuration
. Please see the documentation of theNetworkSslConfig
class for available configuration options.Note that SSL encryption will be applied to all network communications at the cluster node level, thus it is important to make sure that all nodes in the cluster are configured to use SSL encryption. Mixed mode, when some nodes do use SSL and some do not use it, is not supported. In such case non-SSL nodes will not be able to connect to SSL-enabled nodes and vice versa.
Protocol identifier must be specified within the
NetworkConnector
configuration viaNetworkConnectorConfig.setProtocol(String)
method.Data Serialization
Data serialization and deserialization within connectors is handled by the
Codec
interface. Instances of this interface can be specified for each connector independently viaNetworkConnectorConfig.setMessageCodec(CodecFactory)
method. If not specified the the default general purpose codec of aHekate
instance will be used (seeHekateBootstrap.setDefaultCodec(CodecFactory)
).Please see the documentation of
Codec
interface for more details about data serialization.Thread Management
NetworkService
manages a core NIO thread pool ofNetworkServiceFactory.setNioThreads(int)
size. This thread pools is used to process all incoming and outgoing connections by default.It is also possible to configure each
NetworkConnector
to use its own thread pool viaNetworkConnectorConfig.setNioThreads(int)
option. In such case all incoming and outgoing connections of that connector will be handled by a dedicated thread pool of the specified size and will not interfere withNetworkService
's core thread nor with thread pool of any other connector.Whenever a new connection is created by the connector (either
client connection
orNetworkServerHandler.onConnect(Object, NetworkEndpoint)
server connection}) it obtains a worker thread from theNetworkConnector
's thread pool and uses this thread to process all of the NIO events. Due to the event-based nature of NIO each thread can handle multiple connections and doesn't require a one-to-one relationship between the pool size and the amount of active connections. Typically thread pool size must be much less than the number of active connections. When connection gets closed it unregisters itself from its worker thread.Example
The code example below shows how
NetworkService
can be used to implement client/server communications. For the sake of brevity this example uses the default Java serialization and messages ofString
type. For real world applications it is recommended to implement custom message classes and provide a more optimized implementation ofCodec
in order to increase communication speed and to support a more complex application logic.Server Example
1) Prepare server handler.
// Prepare server handler (String - base type of exchanged messages) public class ExampleHandler implements NetworkServerHandler<String> { @Override public void onConnect(String loginMsg, NetworkEndpoint<String> client) { System.out.println("Got new connection: " + loginMsg); // Initialize connection context object. client.setContext(new AtomicInteger()); } @Override public void onMessage(NetworkMessage<String> netMsg, NetworkEndpoint<String> from) throws IOException { String msg = netMsg.decode(); System.out.println("Message from client: " + msg); AtomicInteger counter = (AtomicInteger)from.getContext(); // Send reply. from.send(msg + " processed (total=" + counter.incrementAndGet() + ')'); } @Override public void onDisconnect(NetworkEndpoint<String> client) { System.out.println("Closed connection."); } }
2) Prepare connector configuration.
NetworkConnectorConfig<String> connCfg = new NetworkConnectorConfig<>(); connCfg.setProtocol("example.protocol"); // Protocol identifier. connCfg.setMessageCodec(new JdkCodecFactory<>()); // Use default Java serialization. connCfg.setServerHandler(new ExampleHandler()); // Server handler.
3) Start new node.
// Prepare network service factory and register the connector configuration. NetworkServiceFactory factory = new NetworkServiceFactory() .withPort(10023) // Fixed port for demo purposes. .withConnector(connCfg); // Register the network service factory and start new node. Hekate hekate = new HekateBootstrap() .withService(factory) .join();
Client Example
Note: This example uses the same connector configuration as in the server example.
1) Instantiate a new client and connect to the server.
// Get connector by its protocol identifier. NetworkConnector<String> connector = hekate.network().connector("example.protocol"); NetworkClient<String> client = connector.newClient(); InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 10023); // Asynchronously connect, send a login message (optional) and start receiving messages. client.connect(serverAddress, "example login", (message, from) -> System.out.println("Message from server: " + message) );
2) Start sending messages (can be done even if connection establishment is still in progress).
// Send some messages. for (int i = 0; i < 10; i++) { client.send("Example message", (msg, err) -> { // Check error. if (err == null) { System.out.println("Successfully sent: " + msg); } else { System.err.println("Failed to send: " + err); } }); } // Disconnect and await for completion. client.disconnect().get();
- See Also:
NetworkServiceFactory
-
-
Method Summary
All Methods Instance Methods Abstract Methods Modifier and Type Method Description <T> NetworkConnector<T>
connector(String protocol)
Returns a connector instance for the specifiedprotocol name
.boolean
hasConnector(String protocol)
Returnstrue
if this service has a connector with the specified protocol name.void
ping(InetSocketAddress address, NetworkPingCallback callback)
Asynchronously checks if connection can be established with aNetworkService
at the specified address and notifies the provided callback on operation result.
-
-
-
Method Detail
-
connector
<T> NetworkConnector<T> connector(String protocol) throws IllegalArgumentException
Returns a connector instance for the specifiedprotocol name
.Please see the overview section of this class for more details about connectors.
- Type Parameters:
T
- Base type of connector protocol messages.- Parameters:
protocol
- Protocol name (seeNetworkConnectorConfig.setProtocol(String)
).- Returns:
- TCP connector instance.
- Throws:
IllegalArgumentException
- If there is no such connector with the specified protocol name.
-
hasConnector
boolean hasConnector(String protocol)
Returnstrue
if this service has a connector with the specified protocol name.- Parameters:
protocol
- Protocol name (seeNetworkConnectorConfig.setProtocol(String)
).- Returns:
true
if connector exists.
-
ping
void ping(InetSocketAddress address, NetworkPingCallback callback)
Asynchronously checks if connection can be established with aNetworkService
at the specified address and notifies the provided callback on operation result.Example:
hekate.network().ping(new InetSocketAddress("127.0.0.1", 10012), (address, result) -> { switch (result) { case SUCCESS: { System.out.println("Node is alive at " + address); break; } case FAILURE: { System.out.println("No node at " + address); break; } case TIMEOUT: { System.out.println("Ping timeout " + address); break; } default: { throw new IllegalArgumentException("Unsupported ping result: " + result); } } });
- Parameters:
address
- Address.callback
- Callback to be notified.- See Also:
NetworkPingResult
-
-