Ошибка при чтении файла, используемого двумя отдельными процессами JavaJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Ошибка при чтении файла, используемого двумя отдельными процессами Java

Сообщение Anonymous »

Мне нужно реализовать два объекта игрока в отдельных процессах JAVA. Объекты игрока должны отправлять друг другу сообщения туда и обратно, и между ними должна быть общая переменная-счетчик, к которой должно быть добавлено сообщение, передаваемое между этими объектами.
С каждым сообщение, переменная счетчика должна быть увеличена.
Что я уже реализовал
У меня есть 2 класса. Класс ProcessPlayer и класс Main.

Код: Выделить всё

MainКласс 
создаст два процесса. Каждый игрок принадлежит одному процессу.
Чтобы иметь общую переменную-счетчик, я решил использовать простой текстовый файл, который будет иметь переменную-счетчик и обе процессы будут читать значение, добавлять к сообщению, обновлять значение в файле для следующего процесса. Ниже приведен код класса Main.java.

Код: Выделить всё

public class Main {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("Implementing players on different processes.\n");

Utils.createFile();     // both players on different processes will use this common file.

String classpath = Paths.get(".").toAbsolutePath().normalize().toString();
classpath = classpath + "\\src";

ProcessBuilder secondPlayerProcessBuilder = new ProcessBuilder(
"java", "-cp", classpath, "ProcessPlayer", "Player2", "5003", "5002", "false"
).inheritIO();

ProcessBuilder firstPlayerProcessBuilder = new ProcessBuilder(
"java", "-cp", classpath, "ProcessPlayer", "Player1","5002", "5003", "true"
).inheritIO();

try {
Process secondPlayerProcess = secondPlayerProcessBuilder.start();
Process firstPlayerProcess = firstPlayerProcessBuilder.start();

secondPlayerProcess.waitFor();
firstPlayerProcess.waitFor();

secondPlayerProcess.destroy();
firstPlayerProcess.destroy();

System.out.println("First player process exited with code: " + firstPlayerProcess.exitValue());
System.out.println("Second player process exited with code: " + secondPlayerProcess.exitValue());

Utils.deleteFile();
} catch (IOException | InterruptedException exception) {
exception.printStackTrace();
}
}
Вышеупомянутый класс;
  • Первоначально создает файл со значением счетчика, равным 0.
  • Создает два процесса, в которых выполняются объекты «ProcessPlayer».
Ниже я прилагаю служебные методы, которые использую для взаимодействия. с файлом.

Код: Выделить всё

public class Utils {
public static void createFile() {
try {
if (new File("messageCounter.txt").createNewFile()) {
System.out.println("File Created");
PrintWriter writer = new PrintWriter(new FileWriter("messageCounter.txt"));
writer.print(0);
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

public static void deleteFile() {
boolean isDeleted = new File("messageCounter.txt").delete();
if (isDeleted) {
System.out.println("File removed!");
}
}

public static void updateCounter(int newCounter) throws IOException {
PrintWriter printWriter = new PrintWriter(new FileWriter("messageCounter.txt"));
printWriter.print(newCounter);
printWriter.close();
}
В частности, «updateCounter» — это метод, который будет использоваться обоими процессами во время обратной и обратной связи.
}
В частности, «updateCounter» — это метод, который будет использоваться обоими процессами во время обратной и обратной связи.
}
В частности, «updateCounter» — это метод, который будет использоваться обоими процессами во время обратной и обратной связи. p>
И, наконец, ниже я прикрепляю класс «ProcessPlayer.java».

Код: Выделить всё

public class ProcessPlayer {
int numberOfMessagesSent;
int maxMessages;
static int messageCounter = 0;

boolean isInitiator;
private String playerName;
int port;
int partnerPort;

private ProcessPlayer(ProcessPlayer.PlayerBuilder builder) {
this.numberOfMessagesSent = builder.numberOfMessagesSent;
this.maxMessages = builder.maxMessages;
this.isInitiator = builder.isInitiator;
this.playerName = builder.playerName;
this.port = builder.port;
this.partnerPort = builder.partnerPort;
}

public void start() {
new Thread(this::receiveMessage).start();
if (this.isInitiator) {
sendMessage("HelloWorld!!", true);
}
}

// read counter from file, append it to message and increment it.  Update the file with incremented counter.
public void sendMessage(String message, boolean initialMessage) {
try {
Socket socket = new Socket("localhost", this.partnerPort);
PrintWriter stream = new PrintWriter(socket.getOutputStream(), true);
String senderInfo = "This message was sent from " + this.getPlayerName() + ":";

FileReader fileReader = new FileReader("messageCounter.txt");
int character;
StringBuilder counterFromFile = new StringBuilder();

while (counterFromFile.toString().isEmpty()) {
while ((character = fileReader.read()) != -1) {
counterFromFile.append((char) character);
}
}

fileReader.close();

if (numberOfMessagesSent < maxMessages) {
numberOfMessagesSent++;
if (initialMessage) {
stream.println(senderInfo + message);
}
else if (Integer.parseInt(String.valueOf(counterFromFile)) == 0) {
stream.println(senderInfo + message + counterFromFile);
Utils.updateCounter(Integer.parseInt(counterFromFile.toString()) + 1);
}
else {
stream.println(senderInfo + message + counterFromFile);
Utils.updateCounter(Integer.parseInt(counterFromFile.toString()) + 1);
}
}
} catch(Exception e) {
e.printStackTrace();
}
}

public void receiveMessage() {
try {
ServerSocket serverSocket = new ServerSocket(this.port);
while(numberOfMessagesSent < maxMessages) {
Socket s = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
String message = reader.readLine();
System.out.println(message);
message = message.substring(message.lastIndexOf(":") + 1);
if (messageCounter < maxMessages) {
sendMessage(message, false);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

public String getPlayerName() {
return playerName;
}

public static class PlayerBuilder {
int numberOfMessagesSent;
int maxMessages;
boolean isInitiator;
String playerName;
int port;
int partnerPort;

public PlayerBuilder(int port, int partnerPort) {
this.numberOfMessagesSent = 0;
this.maxMessages = 10;
this.port = port;
this.partnerPort = partnerPort;
}

public ProcessPlayer.PlayerBuilder setInitiator(boolean isInitiator) {
this.isInitiator = isInitiator;
return this;
}

public ProcessPlayer.PlayerBuilder setName(String name) {
this.playerName = name;
return this;
}

public ProcessPlayer build() {
return new ProcessPlayer(this);
}
}

/**
* This method initializes a player instance with the required parameters
* (name, port, and partner's port) and starts the communication process.
* This will be one of the two processes.
* @param args - The value in args array will be passed from Main.java via ProcessBuilderObject
*/
public static void main(String[] args) {
if (args.length != 4) {
System.out.println("Usage: java Player  
  ");
return;
}
String name = args[0];
int port = Integer.parseInt(args[1]);
int partnerPort = Integer.parseInt(args[2]);
boolean isInitiator = Boolean.parseBoolean(args[3]);

try {
ProcessPlayer player = new ProcessPlayer.PlayerBuilder(port, partnerPort)
.setInitiator(isInitiator)
.setName(name).build();
player.start();
} catch (Exception e) {
System.out.println("Exception caught");
throw e;
}
}
Проблема
У меня непоследовательное поведение. Если я полностью перекомпилирую классы «Main.java» и «ProcessPlayer.java» и запущу приложение, я получу следующий результат.

Код: Выделить всё

This message was sent from Player1:HelloWorld!!
This message was sent from Player2:HelloWorld!!0
This message was sent from Player1:HelloWorld!!01
This message was sent from Player2:HelloWorld!!011
This message was sent from Player1:HelloWorld!!0112
This message was sent from Player2:HelloWorld!!01123
This message was sent from Player1:HelloWorld!!011234
This message was sent from Player2:HelloWorld!!0112345
This message was sent from Player1:HelloWorld!!01123456
This message was sent from Player2:HelloWorld!!011234567
и так далее. Как вы можете видеть в приведенном выше выводе, 1 добавляется дважды, этого также не должно происходить. Однако при втором запуске программы я получаю следующую ошибку.

Код: Выделить всё

This message was sent from Player1:HelloWorld!!
This message was sent from Player2:HelloWorld!!0
java.lang.NumberFormatException: For input string: ""
at
java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:565)
at java.base/java.lang.Integer.parseInt(Integer.java:685)
at ProcessPlayer.sendMessage(ProcessPlayer.java:61)
at ProcessPlayer.receiveMessage(ProcessPlayer.java:85)
at java.base/java.lang.Thread.run(Thread.java:1570)
И тогда мне приходится вручную завершать дочерние процессы из CMD. Если вы видите метод sendMessage класса ProcessBuilder.java, я читаю файл посимвольно и создаю строку из asciis, вот откуда эта ошибка. Если я использую объект класса Scanner, он выдает исключение java.util.NoSuchElementException при попытке прочитать файл, указывая, что файл пуст, когда он НЕТ. Благодарим вас за потраченное время. Любая помощь будет очень признательна.

Подробнее здесь: https://stackoverflow.com/questions/786 ... -processes
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»