Java Socket - 从Thread更新实例变量List

时间:2014-02-09 05:55:14

标签: java sockets

我有一个简单的XO游戏,有多个客户互相玩XO Chess。我建立了一个服务器,与每个连接的客户端通信。 (当客户端连接到服务器时,我创建一个新类(实现Runnable)处理该套接字然后启动线程...我有一个List存储外部类中的所有客户端)当客户想要开始游戏时,他使自己成为一个新的服务器,并将房间的信息(他的名字,IP地址,端口......)发送到服务器。在服务器中,我有一个List,它将该房间添加到列表中并将其发送给其他客户端。

    public class ServerController {
private ServerView view;
private ServerSocket myServer;
private int serverPort = 8881;
private List<ExchangeData> list;
private volatile List<Room> rooms;


public ServerController(ServerView view) {
    this.view = view;
    openServer(serverPort);
    view.showMessage("TCP server is running...");
    list = new ArrayList<ExchangeData>();
    rooms = new ArrayList<Room>();
    while (true) {
        listening();
    }

}

private void openServer(int portNumber) {
    ....
}

private void listening() {

    try {
        Socket clientSocket = myServer.accept();

        ExchangeData ex = new ExchangeData(clientSocket);
        Thread thread = new Thread(ex);
        thread.start();
        list.add(ex);

    } catch (IOException e) {
        System.out.print(e.toString());
    }
}

class ExchangeData implements Runnable {
    private Socket clientSocket;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;
    private boolean run = true;

    public ExchangeData(Socket socket) {
        try {
            clientSocket = socket;
            oos = new ObjectOutputStream(clientSocket.getOutputStream());
            ois = new ObjectInputStream(clientSocket.getInputStream());
        } catch (Exception ex) {
            System.out.println(ex.toString());
        }


    }

    public void closeConnection() {
        .....
    }



    public void sendData(Object o) {
        try {

            oos.writeObject(o);
        } catch (Exception ex) {
            view.showMessage(ex.toString());
        }
    }

    public void run() {
        try {

            while (run) {
                Object data = ois.readObject();
                if (data instanceof Object[]) {
                    Object[] o = (Object[]) data;
                    String s = o[0].toString();

                     if (s.equalsIgnoreCase("Open Room")) {

                        Room r = (Room) o[1];
                        String username = r.getUsername();
                        InetSocketAddress isa = r.getIsa();
                        **rooms.add(r);**
                        List<Room> l = new ArrayList<Room>(rooms);

                        for (ExchangeData ex : list) {
                            ex.sendData(username + " Open A room at : "
                                    + isa);
                            **ex.sendData(rooms);**

                        }

                    } else if (s.equalsIgnoreCase("Close Room")) {
                        Room room = (Room) o[1];
                        rooms.remove(room);
                        List<Room> l = new ArrayList<Room>(rooms);
                        for (ExchangeData ex : list) {
                            ex.sendData(l);
                        }
                    } 

                } else if (data instanceof String) {
                    String s = data.toString();
                    if (s.equalsIgnoreCase("Quit")) {
                        stopThread();
                        list.remove(this);
                        closeConnection();

                    } 
                }

            }

        } catch (Exception ex) {
            try {
                stopThread();
                list.remove(this);
            } catch (ExceptionInInitializerError e) {
                e.printStackTrace();

            }
        }
    }
}

}

问题是当我执行rooms.add(r)时,其他人似乎没有看到“更新”。例如: 1)第一个玩家打开一个房间 - 房间大小为1; 2)第二个玩家打开一个新的房间 - 房间大小现在是2(我试图在方法sendData(对象o)的一侧添加一些代码行,其中println的房间大小都是2.但是当行ObjectoutputStream时。执行write(o),它实际上写入Thread(第一个玩家)之前保持的房间的值为1。 如果我创建像List l = new ArrayList(rooms)这样的新列表,就像我在“Closing Room”中所做的那样,那么发送它就可以了。我不明白为什么?有人请向我解释一下。抱歉我的英语不好:(。

1 个答案:

答案 0 :(得分:1)

当您通过给定的ObjectOutputStream多次发送同一个对象时,该流会在第一次写入完整的对象状态,但之后只会向该对象发送一些引用。

这允许使用循环引用发送具有循环引用的对象的复杂图形,而不会消耗太多带宽而不进入无限循环(发送引用B的A,因此发送引用A的B,因此发送引用B的A等)。 / p>

因此,如果您要发送列表的新副本,则必须先使用ObjectOutputStream的reset()方法。