TCP 서버 옵션 추가
This commit is contained in:
@@ -10,17 +10,17 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
|
||||
import com.eactive.testmaster.socket.entity.NettyServerEntity;
|
||||
|
||||
public class NettyServer {
|
||||
private final int port;
|
||||
private final NettyServerEntity config;
|
||||
private EventLoopGroup bossGroup;
|
||||
private EventLoopGroup workerGroup;
|
||||
private Channel serverChannel;
|
||||
private volatile boolean isInitialized = false;
|
||||
private final String script;
|
||||
|
||||
public NettyServer(int port, String script) {
|
||||
this.port = port;
|
||||
this.script = script;
|
||||
public NettyServer(NettyServerEntity config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public synchronized void start() throws InterruptedException {
|
||||
@@ -29,7 +29,6 @@ public class NettyServer {
|
||||
}
|
||||
|
||||
try {
|
||||
// Use custom thread factories to avoid naming conflicts
|
||||
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("netty-boss"));
|
||||
workerGroup = new NioEventLoopGroup(
|
||||
Runtime.getRuntime().availableProcessors() * 2,
|
||||
@@ -45,20 +44,20 @@ public class NettyServer {
|
||||
.childHandler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) {
|
||||
ch.pipeline().addLast(new NettySocketHandler(script));
|
||||
ch.pipeline().addLast(new NettySocketHandler(config.getScript(), config));
|
||||
}
|
||||
});
|
||||
|
||||
// Bind and wait for the server socket
|
||||
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
|
||||
ChannelFuture channelFuture = serverBootstrap.bind(config.getPort()).sync();
|
||||
if (!channelFuture.isSuccess()) {
|
||||
throw new RuntimeException("Failed to bind to port " + port);
|
||||
throw new RuntimeException("Failed to bind to port " + config.getPort());
|
||||
}
|
||||
|
||||
serverChannel = channelFuture.channel();
|
||||
isInitialized = true;
|
||||
|
||||
System.out.println("Netty server started on port " + port);
|
||||
System.out.println("Netty server started on port " + config.getPort());
|
||||
} catch (Exception e) {
|
||||
// Clean up resources if initialization fails
|
||||
stop();
|
||||
@@ -86,7 +85,11 @@ public class NettyServer {
|
||||
}
|
||||
}
|
||||
isInitialized = false;
|
||||
System.out.println("Netty server stopped on port " + port);
|
||||
System.out.println("Netty server stopped on port " + config.getPort());
|
||||
}
|
||||
}
|
||||
|
||||
public NettyServerEntity getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.eactive.testmaster.socket;
|
||||
|
||||
import com.eactive.testmaster.socket.entity.NettyServerEntity;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
@@ -15,8 +16,10 @@ public class NettySocketHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NettySocketHandler.class);
|
||||
private final ScriptEngine engine;
|
||||
private final NettyServerEntity config;
|
||||
|
||||
public NettySocketHandler(String scriptContent) {
|
||||
public NettySocketHandler(String scriptContent, NettyServerEntity config) {
|
||||
this.config = config;
|
||||
ScriptEngineManager manager = new ScriptEngineManager();
|
||||
this.engine = manager.getEngineByName("nashorn");
|
||||
try {
|
||||
@@ -44,7 +47,6 @@ public class NettySocketHandler extends ChannelInboundHandlerAdapter {
|
||||
logger.debug("Received new message from client: {}", ctx.channel().remoteAddress());
|
||||
logger.debug("Total readable bytes: {}", in.readableBytes());
|
||||
|
||||
// Read the entire message as it comes
|
||||
byte[] messageBytes = new byte[in.readableBytes()];
|
||||
in.readBytes(messageBytes);
|
||||
String message = new String(messageBytes);
|
||||
@@ -53,15 +55,18 @@ public class NettySocketHandler extends ChannelInboundHandlerAdapter {
|
||||
logger.debug("- Raw message: {}", message);
|
||||
logger.debug("- Hex dump: {}", bytesToHex(messageBytes));
|
||||
|
||||
// Process the message, removing the length prefix
|
||||
String messageContent = message.substring(4);
|
||||
logger.debug("- Message content (without length): {}", messageContent);
|
||||
// Extract message content based on configuration
|
||||
String messageContent = extractMessageContent(message);
|
||||
String serviceId = extractServiceId(message);
|
||||
|
||||
logger.debug("- Message content: {}", messageContent);
|
||||
logger.debug("- Service ID: {}", serviceId);
|
||||
|
||||
String result;
|
||||
try {
|
||||
logger.debug("Executing script processor for message");
|
||||
Invocable invocable = (Invocable) engine;
|
||||
Object jsResult = invocable.invokeFunction("processMessage", messageContent);
|
||||
Object jsResult = invocable.invokeFunction("processMessage", messageContent, serviceId);
|
||||
result = String.valueOf(jsResult);
|
||||
logger.debug("Script processing successful. Result: {}", result);
|
||||
} catch (ScriptException | NoSuchMethodException e) {
|
||||
@@ -70,20 +75,17 @@ public class NettySocketHandler extends ChannelInboundHandlerAdapter {
|
||||
logger.error("Script execution failed. Using error message as result: {}", result);
|
||||
}
|
||||
|
||||
// Format response with length prefix
|
||||
byte[] responseBytes = result.getBytes();
|
||||
String lengthPrefix = String.format("%04d", responseBytes.length + 4);
|
||||
// Format response with configured prefix
|
||||
byte[] responseBytes = formatResponse(result, serviceId);
|
||||
logger.debug("Preparing response:");
|
||||
logger.debug("- Response content: {}", result);
|
||||
logger.debug("- Response length: {}", responseBytes.length);
|
||||
logger.debug("- Length prefix: {}", lengthPrefix);
|
||||
|
||||
ByteBuf response = ctx.alloc().buffer(4 + responseBytes.length);
|
||||
response.writeBytes(lengthPrefix.getBytes());
|
||||
ByteBuf response = ctx.alloc().buffer(responseBytes.length);
|
||||
response.writeBytes(responseBytes);
|
||||
|
||||
logger.debug("Sending response to client: {}", ctx.channel().remoteAddress());
|
||||
logger.debug("- Total response size: {} bytes", 4 + responseBytes.length);
|
||||
logger.debug("- Total response size: {} bytes", responseBytes.length);
|
||||
ctx.writeAndFlush(response);
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -95,9 +97,71 @@ public class NettySocketHandler extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to convert byte array to hexadecimal string for logging
|
||||
*/
|
||||
private String extractMessageContent(String message) {
|
||||
int prefixSize = config.getPrefixSize().intValue();
|
||||
int serviceIdLength = config.getServiceIdLength().intValue();
|
||||
|
||||
String content = message.substring(prefixSize);
|
||||
|
||||
if (serviceIdLength > 0) {
|
||||
if (config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.START) {
|
||||
content = content.substring(serviceIdLength);
|
||||
} else if (config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.END) {
|
||||
content = content.substring(0, content.length() - serviceIdLength);
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private String extractServiceId(String message) {
|
||||
int prefixSize = config.getPrefixSize().intValue();
|
||||
int serviceIdLength = config.getServiceIdLength().intValue();
|
||||
|
||||
if (serviceIdLength == 0 || config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.NONE) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.START) {
|
||||
return message.substring(prefixSize, prefixSize + serviceIdLength);
|
||||
} else {
|
||||
return message.substring(message.length() - serviceIdLength);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] formatResponse(String result, String serviceId) {
|
||||
byte[] resultBytes = result.getBytes();
|
||||
byte[] serviceIdBytes = serviceId.getBytes();
|
||||
|
||||
int contentLength = resultBytes.length +
|
||||
(config.getServiceIdLength().intValue() > 0 ? serviceIdBytes.length : 0);
|
||||
|
||||
int totalLength = config.getIncludePrefixLength() ?
|
||||
contentLength + config.getPrefixSize().intValue() :
|
||||
contentLength;
|
||||
|
||||
String lengthPrefix = String.format("%0" + config.getPrefixSize() + "d", totalLength);
|
||||
|
||||
ByteBuf buffer = io.netty.buffer.Unpooled.buffer();
|
||||
buffer.writeBytes(lengthPrefix.getBytes());
|
||||
|
||||
if (config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.START) {
|
||||
buffer.writeBytes(serviceIdBytes);
|
||||
buffer.writeBytes(resultBytes);
|
||||
} else {
|
||||
buffer.writeBytes(resultBytes);
|
||||
if (config.getServiceIdPosition() == NettyServerEntity.ServiceIdPosition.END) {
|
||||
buffer.writeBytes(serviceIdBytes);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] responseBytes = new byte[buffer.readableBytes()];
|
||||
buffer.readBytes(responseBytes);
|
||||
buffer.release();
|
||||
|
||||
return responseBytes;
|
||||
}
|
||||
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
@@ -30,12 +32,31 @@ public class NettyServerEntity {
|
||||
@Lob
|
||||
private String script;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "BIGINT DEFAULT 4")
|
||||
private Long prefixSize = 4L;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "BOOLEAN DEFAULT TRUE")
|
||||
private Boolean includePrefixLength = true;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "BIGINT DEFAULT 0")
|
||||
private Long serviceIdLength = 0L;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, columnDefinition = "VARCHAR(10) DEFAULT 'NONE'")
|
||||
private ServiceIdPosition serviceIdPosition = ServiceIdPosition.NONE;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
private LocalDateTime createdAt = LocalDateTime.now();
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
private LocalDateTime lastModified = LocalDateTime.now();
|
||||
|
||||
public enum ServiceIdPosition {
|
||||
NONE,
|
||||
START,
|
||||
END
|
||||
}
|
||||
|
||||
// Standard getters and setters
|
||||
public Long getId() {
|
||||
return id;
|
||||
@@ -97,4 +118,36 @@ public class NettyServerEntity {
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getPrefixSize() {
|
||||
return prefixSize;
|
||||
}
|
||||
|
||||
public void setPrefixSize(Long prefixSize) {
|
||||
this.prefixSize = prefixSize;
|
||||
}
|
||||
|
||||
public Boolean getIncludePrefixLength() {
|
||||
return includePrefixLength;
|
||||
}
|
||||
|
||||
public void setIncludePrefixLength(Boolean includePrefixLength) {
|
||||
this.includePrefixLength = includePrefixLength;
|
||||
}
|
||||
|
||||
public Long getServiceIdLength() {
|
||||
return serviceIdLength;
|
||||
}
|
||||
|
||||
public void setServiceIdLength(Long serviceIdLength) {
|
||||
this.serviceIdLength = serviceIdLength;
|
||||
}
|
||||
|
||||
public ServiceIdPosition getServiceIdPosition() {
|
||||
return serviceIdPosition;
|
||||
}
|
||||
|
||||
public void setServiceIdPosition(ServiceIdPosition serviceIdPosition) {
|
||||
this.serviceIdPosition = serviceIdPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class NettyServerService {
|
||||
}
|
||||
|
||||
if (!activeServers.containsKey(entity.getPort())) {
|
||||
NettyServer server = new NettyServer(entity.getPort(), entity.getScript());
|
||||
NettyServer server = new NettyServer(entity);
|
||||
server.start();
|
||||
activeServers.put(entity.getPort(), server);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user