#java #multithreading #sockets
#java #многопоточность #сокеты
Вопрос:
Я пишу игру, но теперь у меня проблема с серверным / клиентским сокетом. Игра хорошо работает, когда я играю локально, а также когда я играю онлайн с RMI. Проблема возникает, когда я пытаюсь реализовать сокет (я должен сделать также сокет). Вот как я реализовал код (я использую шаблон Model-View-Controller):
СЕРВЕР: Класс SocketServerCreate: создайте сервер, а затем создайте поток для получения соединения (SocketServerConnection), который затем создаст другой поток для получения сообщения всеми клиентами (SocketServerReceive). Сервер также создает экземпляр объекта, который реализует Observer, который вызывается моделью для отправки информации клиенту (SocketServerOutput).
КЛИЕНТ: Класс SocketClientCreate: откройте соединение с сервером, затем создайте поток для получения сообщения сервером и создайте экземпляр класса, который реализует Observer, который вызывается представлением для отправки информации на сервер.
Проблема в том, что метод обновления сервера, который находится в классе SocketServerOutput, вызывается много раз, но его нужно вызвать только один раз, чтобы отправить сообщение клиенту. Чтобы быть ясным, я публикую весь код сервера и клиента.
SocketServerCreate
/*
* This class creates the server.
*/
public class SocketServerCreate {
private static final int PORT = 5000;
private ArrayList<ObjectOutputStream> arrayPlayerSocket;
private SocketServerOutput outputServer;
public SocketServerCreate(Model model){
ServerSocket serverSocket;
Controller controller = new Controller(model);
arrayPlayerSocket = new ArrayList<ObjectOutputStream>();
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
System.out.println("Error during the creation of the Server.n" e.getStackTrace());
return;
}
outputServer = new SocketServerOutput(this, controller);
SocketServerConnection connectionServer = new SocketServerConnection(this, serverSocket, controller);
Thread receiveServerThread = new Thread(connectionServer);
receiveServerThread.start();
}
public void addPlayerSocket(ObjectOutputStream outputStream){
arrayPlayerSocket.add(outputStream);
}
public ArrayList<ObjectOutputStream> getArrayPlayerSocket(){
return (ArrayList<ObjectOutputStream>) arrayPlayerSocket;
}
public SocketServerOutput getSocketServerOutput(){
return outputServer;
}
}
Вывод SocketServerOutput
/*
* This class manages the object that must be send to the client.
*/
public class SocketServerOutput implements Observer {
ArrayList<ObjectOutputStream> arrayPlayersSocket;
SocketServerCreate socketServerCreate;
Controller controller;
private ObjectOutputStream outputMessage = null;
public SocketServerOutput(SocketServerCreate socketServerCreate, Controller controller){
this.socketServerCreate = socketServerCreate;
this.controller = controller;
}
@Override
public void update(Observable o, Object arg) {
if(o.equals(controller.getModel().getModelChanges())){
arrayPlayersSocket = socketServerCreate.getArrayPlayerSocket();
Iterator<ObjectOutputStream> arrayIterator = arrayPlayersSocket.iterator();
while(arrayIterator.hasNext()){
outputMessage = (ObjectOutputStream)arrayIterator.next();
try {
outputMessage.writeObject(arg);
outputMessage.flush();
/*if(arrayPlayersSocket.indexOf(outputMessage) != controller.getTurn().getCurrentPlayer()){
ModelChanges modelChanges = new ModelChanges();
modelChanges.spegniBottoniOnLine(false, false, false);
outputMessage.writeObject(modelChanges);
outputMessage.flush();
}*/
} catch (IOException e) {
System.out.println("IOException while the server sends an object to the client!");
return;
}
}
}
}
}
SocketServerConnection
public class SocketServerConnection implements Runnable {
private ServerSocket serverSocket;
private SocketServerCreate socketServerCreate;
private Controller controller;
public SocketServerConnection(SocketServerCreate socketServerCreate, ServerSocket serverSocket, Controller controller){
this.socketServerCreate = socketServerCreate;
this.serverSocket = serverSocket;
this.controller = controller;
}
@Override
public void run() {
while(true){
try {
Socket lastSocket = serverSocket.accept();
ObjectOutputStream outputMessage = new ObjectOutputStream(lastSocket.getOutputStream());
socketServerCreate.addPlayerSocket(outputMessage);
//send to the view the index where the client is setted in the server array
outputMessage.writeObject((Integer)socketServerCreate.getArrayPlayerSocket().lastIndexOf(outputMessage));
outputMessage.flush();
SocketServerReceive receiveServer = new SocketServerReceive(lastSocket, controller);
Thread receiveThread = new Thread(receiveServer);
receiveThread.start();
} catch (IOException e) {
System.out.println("IOException while the server accept the client.n" e.getCause());
}
}
}
}
SocketServerReceive
public class SocketServerReceive implements Runnable {
private ObjectInputStream inputMessage = null;
private Controller controller;
private Object message;
public SocketServerReceive(Socket socket, Controller controller){
this.controller = controller;
System.out.println("Connection created with the client that has IP Address: " socket.getInetAddress());
if(inputMessage == null){
try {
inputMessage = new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
System.out.println("IOException while the server are creating a stream with the client.n" e.getCause());
}
}
}
@Override
public void run() {
while(true){
try {
message = inputMessage.readObject();
controller.receiveMessageView(message);
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException in SocketServerReceive.n" e.getStackTrace());
return;
} catch (IOException e) {
}
}
}
}
SocketClientCreate
/*
* This class starts a connection with the Server and then it creates two threads,
* one to manage the input request, the other to manage the output request
*/
public class SocketClientCreate {
private static final int PORT = 5000;
private Socket serverSocket;
private int arrayIndex;
private SocketClientOutput outputClient;
public SocketClientCreate(String ipAddress, View view){
try {
serverSocket = new Socket(ipAddress, PORT);
} catch (UnknownHostException e) {
System.out.println("UnknownHostException during the connection of the Client at the Server");
return;
} catch (IOException e) {
System.out.println("IOException during the connection of the Client at the Server");
return;
}
outputClient = new SocketClientOutput(this, serverSocket, view);
SocketClientReceive receiveClient = new SocketClientReceive(this, serverSocket, view);
Thread receiveThread = new Thread(receiveClient);
receiveThread.start();
}
public SocketClientOutput getOutputClient(){
return outputClient;
}
public void setArrayIndex (Integer arrayIndex){
this.arrayIndex = arrayIndex;
}
public int getArrayIndex(){
return arrayIndex;
}
}
SocketClientOutput
/*
* This class manages all the message that the client must send to the server. Its methods
* are called by update method.
*/
public class SocketClientOutput implements Observer {
private ObjectOutputStream outputMessage = null;
private View view;
private SocketClientCreate socketClientCreate;
public SocketClientOutput(SocketClientCreate socketClientCreate, Socket server, View view){
this.view = view;
this.socketClientCreate = socketClientCreate;
if(outputMessage == null){
try {
outputMessage = new ObjectOutputStream(server.getOutputStream());
} catch (IOException e) {
System.out.println("IOException at the opening of the output stream between the client and the server.n" e.getCause());
return;
}
}
}
/*
* update receive an object from the view and send this object to the server.
*/
@Override
public void update(Observable o, Object arg) {
if(o.equals(view)){
/*
* GESTIRE INDICE CREAZIONE GIOCATORE
*/
try {
outputMessage.writeObject(arg);
outputMessage.flush();
} catch (IOException e) {
System.out.println("IOException while the client sends an object to the server.n" e.getCause());
return;
}
}
}
}
SocketClientReceive
/*
* This class waits an object from the server and then modify the view.
*/
public class SocketClientReceive implements Runnable {
private ObjectInputStream inputMessage = null;
private View view;
private SocketClientCreate socketClientCreate;
private Object message;
public SocketClientReceive(SocketClientCreate socketClientCreate, Socket server, View view){
this.view = view;
this.socketClientCreate = socketClientCreate;
if(inputMessage == null){
try {
inputMessage = new ObjectInputStream(server.getInputStream());
} catch (IOException e) {
System.out.println("IOException at the opening of the input stream between the client and the server.n" e.getStackTrace());
}
}
}
@Override
public void run() {
while(true){
try {
message = inputMessage.readObject();
if(message instanceof Integer){
socketClientCreate.setArrayIndex((Integer)message);
}else if(message instanceof ModelChanges){
ModelChanges modelChanges = (ModelChanges)message;
view.getMappa().repaintView(modelChanges);
}
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException waiting a message from the server!n" e.getStackTrace());
return;
} catch (IOException e) {
}
}
}
}
Ответ №1:
Я бы посоветовал вам создать логическое значение, которое включено по умолчанию, но становится false, когда сервер отправляет сообщение. Затем, когда сервер намеревается отправить другое сообщение, turn оно должно стать true . Свяжитесь со мной, если это было то, что вы имели в виду, или если вы ищете что-то еще.
private Object lastMessage;
private boolean hasSentMessage;
@Override
public void update(Observable o, Object arg) {
//Check if the message is the same as the last message.
if(!arg.equals(lastMessage))
hasSentMessage = false;
//Also check if it has already sent a message.
if(o.equals(controller.getModel().getModelChanges()) amp;amp; !hasSentMessage){
arrayPlayersSocket = socketServerCreate.getArrayPlayerSocket();
Iterator<ObjectOutputStream> arrayIterator = arrayPlayersSocket.iterator();
while(arrayIterator.hasNext()){
outputMessage = (ObjectOutputStream)arrayIterator.next();
try {
outputMessage.writeObject(arg);
outputMessage.flush();
//State that the message has been sent.
hasSentMessage = true;
lastMessage = arg;
/*if(arrayPlayersSocket.indexOf(outputMessage) != controller.getTurn().getCurrentPlayer()){
ModelChanges modelChanges = new ModelChanges();
modelChanges.spegniBottoniOnLine(false, false, false);
outputMessage.writeObject(modelChanges);
outputMessage.flush();
}*/
} catch (IOException e) {
System.out.println("IOException while the server sends an object to the client!");
return;
}
}
}
}
Комментарии:
1. спасибо за ответ. Я не могу использовать этот способ, потому что модель отправляет один и тот же объект, но с другой переменной. есть способ использовать этот метод, но адаптировать его к моей ситуации?