CTimet 2022-05-08 18:28 采纳率: 84%
浏览 14
已结题

本地Java程序与本地服务器交互答非所问

事情是这样的。我写了一个mc插件,然后用集合保存的数据,正常开启与关闭是会正常读取和保存数据的。然后有个人就问我如果程序突然崩溃导致数据丢失那怎么办。诚然,这种情况不是不可能。因为mc服崩溃是在个别服务器中比较常见的事情。那这时候数据就会丢失。为了保护玩家数据,我想出了这样一个法子:
1.启动插件
2.让插件去启动本地服务器
3.本地服务器监听8189号端口
4.插件与服务器通过8189号端口进行数据交互
5.服务器保存数据
这样一套流程下来,就算插件崩了,数据也不会丢失,因为数据服务器是独立于插件之外的一个程序。插件只不过是执行了cmd命令让他启动罢了。不过尽管如此,还是有个很麻烦的问题。这个第4步,插件与服务器进行交互的问题让我很头疼。因为此话题与MC无关,所以我们只讨论Java程序与本地服务器进行交互的问题。
我是这么想的,可以利用PrintWrinter与服务器进行交互,看起来就像用telnet交互一样,为了测试插件和服务器交互成果,我写了个这么个玩意:

package me.ctimet.dataserver;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        Socket socket = new Socket("127.0.0.1",8189);
        Scanner scanner = new Scanner(socket.getInputStream(), StandardCharsets.UTF_8);
        PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),StandardCharsets.UTF_8),true);
        Scanner sc = new Scanner(System.in);
        while (true)
        {
            System.out.println(scanner.nextLine());
            printWriter.println(sc.nextLine());
        }
    }
}

我依靠这个程序与服务器进行交互。但是,在测试过程中,我发现了一个很严重的问题,就是答非所问,请看这张图:

img


这是刚刚服务器与交互程序交互的场景,可以很明显的发现,我在键入put 1 1 1之后键入get 1,服务器返回了Null,这是不理想状况。因为理想状况应该是返回1才对。put指令是向服务器内存入数据,其中第一个1代表locationKey,第二个1代表key,第三个则代表value。这是对应的方法

img


这是服务器的类文件

package me.ctimet.dataserver;

import me.ctimet.dataserver.password.MakePassword;
import me.ctimet.dataserver.thread.ThreadedEchoHandler;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;

public class Main
{
    public static final HashSet<Thread> threads = new HashSet<>();

    public static void main(String[] args) throws IOException
    {
        init();
        start();
    }

    public static void init() throws IOException
    {
        MakePassword.make();
    }

    public static void start()
    {
        try (ServerSocket socket = new ServerSocket(8189))
        {
            while (true)
            {
                Socket incoming = socket.accept();
                Runnable run = new ThreadedEchoHandler(incoming);
                Thread thread = new Thread(run);
                thread.start();
                threads.add(thread);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public static void stop()
    {
        System.exit(0);
    }
}
package me.ctimet.dataserver.data;

import java.util.HashMap;

public class Data
{
    private static final HashMap<String,String> FIX = new HashMap<>();
    private static final HashMap<String,String> LOC = new HashMap<>();

    public static String get(String key)
    {
        return FIX.get(key);
    }

    public static void put(String locationKey,String key,String value)
    {
        FIX.put(key,value);
        LOC.put(locationKey,key);
    }

    public static void clear()
    {
        FIX.clear();
        LOC.clear();
    }

    public static void remove(String locationKey)
    {
        String key = LOC.get(locationKey);
        FIX.remove(key);
        LOC.remove(locationKey);
    }

    public static boolean containsKey(String key)
    {
        return FIX.containsKey(key);
    }

    public static boolean containsLocationKey(String key)
    {
        return LOC.containsKey(key);
    }
}
package me.ctimet.dataserver.thread;

import me.ctimet.dataserver.Main;
import me.ctimet.dataserver.password.MakePassword;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

import static me.ctimet.dataserver.data.Data.*;

public class ThreadedEchoHandler implements Runnable
{
    Socket socket;

    public ThreadedEchoHandler(Socket s)
    {
        socket = s;
    }

    public void run()
    {
        try (InputStream in = socket.getInputStream();
                OutputStream out = socket.getOutputStream();
                Scanner sc = new Scanner(in, StandardCharsets.UTF_8);
                PrintWriter pr = new PrintWriter(new OutputStreamWriter(out,StandardCharsets.UTF_8),true))
        {
            pr.println("Type the password:");
            while (sc.hasNextLine())
            {
                if  (sc.nextLine().equals(MakePassword.pps.getProperty("pw")))
                {
                    doing(sc, pr);
                    break;
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public void doing(Scanner sc, PrintWriter pr)
    {
        pr.println("Connect succeed");
        Say say = new Say(pr);
        String command;
        String argsGet;
        String[] argsPut;
        while (sc.hasNextLine())
        {
            command = sc.nextLine();
            argsGet = subArgsForGet(command);
            argsPut = subArgsForPut(command);
            switch (subCommand(command))
            {
                case "get" -> say.say(get(argsGet));
                case "put" -> {
                    put(argsPut[0],argsPut[1],argsPut[2]);
                    //say.say(argsPut[0]);
                    //say.say(argsPut[1]);
                    //say.say(argsPut[2]);
                    say.say("Type...");
                }
                case "stop" -> Main.stop();
                case "clear" -> {
                    clear();
                    say.say("Type...");
                }
                case "delete" -> {
                    remove(argsGet);
                    say.say("Type...");
                }
                case "continue" -> {
                    ThreadContinue.time = 3;
                    say.say("Type...");
                }
                case "containsKey" -> say.say(String.valueOf(containsKey(argsGet)));
            }
        }
    }

    String subCommand(String com)
    {
        for (int i = 0; i < com.length(); i ++)
        {
            if (com.charAt(i) == ' ')
            {
                return com.substring(0,i);
            }
        }
        return "";
    }

    String subArgsForGet(String com)
    {
        for (int i = 0; i < com.length(); i ++)
        {
            if (com.charAt(i) == ' ')
            {
                return com.substring(i+2);
            }
        }
        return "";
    }

    String[] subArgsForPut(String com)
    {
        String lk = subCommand(subArgsForGet(com));
        String k = subArgsForGet(subArgsForGet(com));
        String v = subArgsForGet(subArgsForGet(subArgsForGet(com)));
        return new String[]{lk,k,v};
    }
    
    static class Say
    {
        PrintWriter pr;
        public Say(PrintWriter printWriter)
        {
            pr = printWriter;
        }
        public void say(String mes)
        {
            pr.println(mes);
        }
    }
}
package me.ctimet.dataserver.thread;

public class ThreadContinue
{
    public static int time = 3;
}
package me.ctimet.dataserver.password;

import org.jetbrains.annotations.NotNull;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Random;

public class MakePassword
{
    public static final Properties pps = new Properties();

    public static void make() throws IOException
    {
        pps.load(new FileReader("resource/pw.properties"));
        String pw = getRandomPassword();
        pps.setProperty("pw",pw);
        pps.store(new FileWriter("resource/pw.properties"),pw);
    }

    @NotNull
    public static String getRandomPassword()
    {
        Random r = new Random();
        String password = "";
        while (password.length() < 50)
        {
            password = password + r.nextInt(10);
        }
        return password;
    }
}

非常感谢!

  • 写回答

1条回答 默认 最新

  • 三千烦恼丝xzh 2022-05-08 19:16
    关注

    debug在map get哪行打个点看下是不是字符串拆分入参有问题,最好是一段一段逻辑排查,Java debug要比c友好很多,我看你写的代码似c的风格

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 5月16日
  • 已采纳回答 5月8日
  • 创建了问题 5月8日

悬赏问题

  • ¥20 西南科技大学数字信号处理
  • ¥15 有两个非常“自以为是”烦人的问题急期待大家解决!
  • ¥30 STM32 INMP441无法读取数据
  • ¥15 R语言绘制密度图,一个密度曲线内fill不同颜色如何实现
  • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件文件升级包
  • ¥15 用visualstudio2022创建vue项目后无法启动
  • ¥15 x趋于0时tanx-sinx极限可以拆开算吗
  • ¥15 pyqt信号槽连接写法
  • ¥500 把面具戴到人脸上,请大家贡献智慧,别用大模型回答,大模型的答案没啥用
  • ¥15 任意一个散点图自己下载其js脚本文件并做成独立的案例页面,不要作在线的,要离线状态。