Локальный сервер сокета Java - PullRequest
1 голос
/ 16 апреля 2019

Моя цель состояла в том, чтобы создать Java-сервис в Windows, который будет работать локально и взаимодействовать с локальными программами с использованием JSON. Услуга должна быть надежной и надежной.

Служба запускает ServerSocket и получает и отвечает на сообщения JSON. Ниже приведен скелет, в котором соответствующие «команды» будут добавлены в класс SigningController. Сервис, скорее всего, останется небольшим и будет содержать ~ 10 различных команд.

Вопросы

Является ли сервер надежным (т. Е. Нет потенциальных зависаний, исключений и т. Д.)?

Я заметил, что после интенсивного использования (отправка большого количества команд "echo" с большими строками) использование памяти увеличивается до ~ 530 МБ, а затем медленно уменьшается. У меня есть утечка ресурсов или памяти, или это стандартное поведение JVM?

Может быть, не по теме, но есть ли способ изменить имя и значок задачи, которые отображаются в диспетчере задач? В настоящее время этот процесс отображается как «двоичный файл Java (TM) Platform SE».

Служба установлена ​​с 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

start.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>

Main

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);
        }
    }
}

Utils

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();
    }
}

SigningController

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();
            }
        }
    }
}
...