【问题标题】:Client/Server Socket Java (pattern MVC) doesn't send correct information to the Client客户端/服务器套接字 Java(模式 MVC)不向客户端发送正确的信息
【发布时间】:2014-06-21 17:19:23
【问题描述】:

我正在编写游戏,但现在我遇到了服务器/客户端套接字的问题。当我在本地玩游戏以及使用 RMI 在线玩游戏时,该游戏运行良好。当我尝试实现套接字时出现问题(我也必须做套接字)。这就是我实现代码的方式(我使用模型-视图-控制器模式):

服务器: SocketServerCreate类:创建服务器,然后创建一个线程来接收连接(SocketServerConnection),然后创建另一个线程来接收所有客户端的消息(SocketServerReceive)。服务器还实例化了一个对象,该对象实现了模型调用的 Observer 以向客户端发送信息(SocketServerOutput)。

客户: SocketClientCreate类:打开与服务端的连接,然后创建一个线程接收服务端消息,并实例化一个实现观察者的类,视图调用该观察者向服务端发送信息。

问题是SocketServerOutput类中的Server的update方法被调用了很多次,但必须只调用一次才能将消息发送给客户端。需要说明的是,我发布了服务器和客户端的所有代码。

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) {

        }
    }

}

}

【问题讨论】:

    标签: java multithreading sockets


    【解决方案1】:

    我建议您创建一个布尔值,默认情况下启用,但在服务器发送消息时变为 false。然后,当服务器打算发送另一条消息时,它应该变为真。如果这是您的想法,或者您正在寻找其他东西,请与我联系。

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

    【讨论】:

    • 感谢您的回答。我不能使用这种方式,因为模型发送相同的对象但具有不同的变量。有一种方法可以使用这种方法,但可以根据我的情况进行调整?
    猜你喜欢
    • 2013-04-01
    • 2016-08-31
    • 1970-01-01
    • 2023-03-08
    • 2014-05-12
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    相关资源
    最近更新 更多