我的目标是在 Windows 上创建一个在本地运行并使用 JSON 与本地程序通信的 Java 服务。服务应该是可靠和健壮的。
该服务运行一个 ServerSocket 并接收接收和响应 JSON 消息。以下是一个框架,其中适当的“命令”将添加到 SigningController 类中。该服务可能会保持小规模,并将包含约 10 个不同的命令。
问题
服务器看起来是否可靠(即没有潜在的挂断、异常等)?
我注意到,在大量使用之后(发送大量带有大字符串的“echo”命令),内存使用量增加到约 530mb,然后慢慢下降。我有资源或内存泄漏还是标准 JVM 行为?
也许题外话,但有没有办法改变任务管理器中显示的任务名称和图标?目前该进程显示为“Java(TM) Platform SE binary”。
该服务与nssm和 bat 文件一起安装
install.bat(以管理员身份)
@echo off
pushd %~dp0
nssm.exe stop JavaSigningService
nssm.exe remove JavaSigningService confirm
nssm.exe install JavaSigningService %~dp0start.bat
nssm.exe start JavaSigningService
popd
pause
开始.bat
java -Xmx512m -jar signingservice.jar
POM 文件和下面的类。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>Server.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>signingservice</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>signingservice</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
</project>
主要的
package Server;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
try (ServerSocket listener = new ServerSocket(port)) {
System.out.println("Server is running...");
ExecutorService pool = Executors.newFixedThreadPool(10);
while (true) {
try {
pool.execute(new Signer(listener.accept()));
} catch (Exception e){
// Log
}
}
} catch (Exception e) {
// Log
} finally {
System.exit(0);
}
}
}
实用程序
package Server;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.PrintWriter;
import java.io.StringWriter;
public class Utils {
private static JsonParser parser = new JsonParser();
public static JsonObject getJsonFromString(String str) throws Exception{
JsonObject jsonObject = parser.parse(str).getAsJsonObject();
return jsonObject;
}
public static String getJsonProperty(JsonObject json, String property){
String value = null;
try {
value = json.get(property).getAsString();
} catch (Exception e) {}
return value;
}
public static JsonObject errorMessageTemplate(Exception e){
JsonObject result = new JsonObject();
result.addProperty("result", "ERROR");
result.addProperty("errormessage", e.getMessage());
result.addProperty("stacktrace", stackTraceAsString(e));
return result;
}
public static String stackTraceAsString(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
}
签名控制器
package Server;
import com.google.gson.JsonObject;
public class SigningController {
public static JsonObject handle(JsonObject received) throws Exception{
String command = Utils.getJsonProperty(received, "command");
if("echo".equals(command)){
return simpleEcho(received);
}
return Utils.errorMessageTemplate(new Exception("Command not specified or unknown."));
}
public static JsonObject simpleEcho(JsonObject received) throws Exception{
String data = "" + Utils.getJsonProperty(received, "data");
JsonObject result = new JsonObject();
result.addProperty("result", "OK");
result.addProperty("data", data);
return result;
}
}
签名者
package Server;
import com.google.gson.JsonObject;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Signer implements Runnable{
private Socket socket;
private BufferedReader socketIn;
private PrintWriter socketOut;
Signer(Socket socket) throws IOException {
this.socket = socket;
this.socket.setSoTimeout(60*1000); // read timeout in milliseconds
socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
socketOut = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
}
@Override
public void run() {
System.out.println("Connected: " + socket);
try {
socketOut.println("hello");
String line = socketIn.readLine();
JsonObject json = Utils.getJsonFromString(line);
JsonObject result = SigningController.handle(json);
socketOut.println(result);
} catch (Exception e){
// Log
System.out.println("Error: " + socket);
e.printStackTrace();
try {
socketOut.println(Utils.errorMessageTemplate(e));
} catch (Exception e1) {}
} finally{
// Cleanup
try{
socketIn.close();
} catch (IOException e){
e.printStackTrace();
}
try{
socketOut.close();
} catch (Exception e){
e.printStackTrace();
}
try{
socket.close();
System.out.println("Closed: " + socket);
} catch (IOException e){
e.printStackTrace();
}
}
}
}