Deep Dive into smart‑socket’s Built‑In Plugin System
This article explains smart‑socket’s extensible plugin architecture, detailing the Plugin and AbstractPlugin interfaces, and demonstrates how to integrate built‑in plugins such as SSL/TLS encryption, heartbeat detection, blacklist filtering, memory‑pool monitoring, traffic logging, socket option configuration, and idle‑state handling, while covering plugin ordering, custom development, performance considerations, and best‑practice recommendations.
Plugin Architecture
smart‑socket plugin system is based on the Plugin interface, which extends NetMonitor . It defines three extension points:
preProcess : preprocesses a request message and decides whether the message should continue to MessageProcessor.process. Returning false drops the message.
stateEvent : listens to state‑machine events for a session.
NetMonitor methods: monitor connection acceptance, read/write operations, etc.
public interface Plugin<T> extends NetMonitor {
boolean preProcess(AioSession session, T t);
void stateEvent(StateMachineEnum stateMachineEnum, AioSession session, Throwable throwable);
}To simplify development, AbstractPlugin provides empty implementations of all Plugin methods.
public abstract class AbstractPlugin<T> implements Plugin<T> {
@Override public boolean preProcess(AioSession session, T t) { return true; }
@Override public void stateEvent(StateMachineEnum stateMachineEnum, AioSession session, Throwable throwable) {}
// other NetMonitor methods have empty bodies
}Plugins are added to a MessageProcessor via addPlugin and the processor is passed to an AioQuickServer instance.
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
// handle message
}
};
processor.addPlugin(new SslPlugin<>());
processor.addPlugin(new HeartPlugin<>());
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();SSL/TLS Security Plugin
SslPlugin provides SSL/TLS encryption by wrapping the underlying AsynchronousSocketChannel.
public class SslServerExample {
public static void main(String[] args) throws Exception {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received encrypted message: " + msg);
}
};
ServerSSLContextFactory factory = new ServerSSLContextFactory();
factory.keystore("keystore.jks", "password");
SslPlugin<String> sslPlugin = new SslPlugin<>(factory);
processor.addPlugin(sslPlugin);
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Heartbeat Detection Plugin
HeartPlugin detects active connections and prevents dead connections caused by network anomalies.
public class CustomHeartPlugin extends HeartPlugin<String> {
public CustomHeartPlugin() {
super(30, 60, TimeUnit.SECONDS); // interval 30 s, timeout 60 s
}
@Override public void sendHeartRequest(AioSession session) throws IOException {
byte[] heartMsg = "PING".getBytes();
session.writeBuffer().writeInt(heartMsg.length);
session.writeBuffer().write(heartMsg);
}
@Override public boolean isHeartMessage(AioSession session, String msg) {
return "PING".equals(msg) || "PONG".equals(msg);
}
} public class HeartPluginExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
if ("PING".equals(msg)) {
byte[] resp = "PONG".getBytes();
session.writeBuffer().writeInt(resp.length);
session.writeBuffer().write(resp);
session.writeBuffer().flush();
} else {
System.out.println("Received message: " + msg);
}
}
};
processor.addPlugin(new CustomHeartPlugin());
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Blacklist Plugin
BlackListPlugin rejects connections from specific IP addresses or port ranges.
public class BlackListExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received message: " + msg);
}
};
BlackListPlugin<String> blackListPlugin = new BlackListPlugin<>();
// Reject a specific IP
blackListPlugin.addRule(address -> !"192.168.1.100".equals(address.getAddress().getHostAddress()));
// Reject ports outside 10000‑20000
blackListPlugin.addRule(address -> {
int port = address.getPort();
return port < 10000 || port > 20000;
});
processor.addPlugin(blackListPlugin);
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Memory‑Pool Monitoring Plugin
BufferPageMonitorPlugin monitors the usage of the memory pool.
public class BufferPageMonitorExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received message: " + msg);
}
};
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
// Output memory‑pool status every 6 seconds
processor.addPlugin(new BufferPageMonitorPlugin<>(server, 6));
server.start();
}
}Traffic Monitoring Plugin
StreamMonitorPlugin logs the data flow of the network layer, showing hex dumps in real time.
public class StreamMonitorExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received message: " + msg);
}
};
processor.addPlugin(new StreamMonitorPlugin<>());
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Sample console output:
2023-01-01 10:00:00.123 [ /127.0.0.1:56789 --> /127.0.0.1:8888 ] [ read: 12 bytes ]
00000000h: 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 ; Hello World!Socket Option Plugin
SocketOptionPlugin configures various socket options.
public class SocketOptionExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received message: " + msg);
}
};
SocketOptionPlugin<String> socketOptionPlugin = new SocketOptionPlugin<>();
socketOptionPlugin.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
socketOptionPlugin.setOption(StandardSocketOptions.SO_RCVBUF, 1024 * 1024);
socketOptionPlugin.setOption(StandardSocketOptions.SO_SNDBUF, 1024 * 1024);
processor.addPlugin(socketOptionPlugin);
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Idle‑State Plugin
IdleStatePlugin detects idle connections and automatically closes them after a configured period without read/write activity.
public class IdleStateExample {
public static void main(String[] args) throws IOException {
MessageProcessor<String> processor = new AbstractMessageProcessor<>() {
@Override public void process0(AioSession session, String msg) {
System.out.println("Received message: " + msg);
}
};
// Close connection if idle for 60 seconds
processor.addPlugin(new IdleStatePlugin<>(60));
AioQuickServer<String> server = new AioQuickServer<>(8888, new StringProtocol(), processor);
server.start();
}
}Plugin Execution Order
Plugins execute in the order they are added. If any plugin’s preProcess returns false, subsequent plugins are skipped and the message is not passed to the MessageProcessor.
// Example order
processor.addPlugin(plugin1); // executed first
processor.addPlugin(plugin2); // executed second
processor.addPlugin(plugin3); // executed lastBest‑Practice Recommendations
Use plugins wisely: select only needed plugins to avoid unnecessary performance overhead.
Mind plugin order: execution order can affect functionality; arrange accordingly.
Custom plugin development: inherit AbstractPlugin for special requirements.
Monitor plugin performance: monitoring plugins may introduce overhead; balance monitoring needs with performance.
Exception handling: handle exceptions inside plugins to prevent disruption of the main processing flow.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Three Knives
Every line of code you contribute to open source could help make the future better.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
