0

在Java中,我试图将BufferedOutputStream服务器生成的每个存储到线程之外的数组中,以便向所有连接的客户端广播一些数据。

// initialisation
   ArrayList<BufferedOutputStream> connections = new ArrayList<BufferedOutputStream>();
// when a client connects
   Socket connection = socket.accept();
   connections[id] = connection;
// broadcasting to all clients
   for (int i = 0; i < connections.size(); i++) {
      try {
         OutputStreamWriter osw = new OutputStreamWriter(connections.get(i), "US-ASCII");
         osw.write(s + "\n");
         osw.flush();
      } catch (Exception g) {
         // catch
      }
   }

注意:仅给出基本代码

问题:广播循环只广播到循环中的第一个,有时也广播到其他人。没有错误被抛出,并且循环迭代应该如此。

出了什么问题,我该如何解决?这可能很明显,但我仍然是初学者..

谢谢!

4

4 回答 4

2

我们无法准确告诉您出了什么问题,因为您遗漏了代码的重要部分。但是,如果是connections[id] = connection抛出一个 NPE,那只能意味着. 而且,从表面上看,您似乎没有初始化为非空值!connectionsnullconnections

解决方法是初始化连接……某处……到适当大小的数组。但是,这会给您带来其他问题。id数组的合适大小是多少,当大于时你要做什么connections.length

根本问题是数组(可能)是保持连接的糟糕选择......

于 2013-10-21T18:28:26.920 回答
1

也许套接字已经关闭,或者i数组中的索引为空,所以问题是,你为什么不使用List<OutputStream>over Socket[]

List<OutputStream>或者List<OutputStreamWriter>你不需要在OutputStreamWriter每次你想发送一些数据时初始化。

于 2013-10-21T18:28:22.753 回答
0

不知何故你应该存储客户端套接字对象。每当您想广播时,遍历集合获取套接字,从中获取输出流,然后写入套接字。它为我正常工作。

于 2013-10-21T18:27:50.330 回答
0

编辑:Socket[] array = new Socket[#];

你永远不会初始化你的数组。这可能是问题所在。但我建议使用 aList或 a Map。显然,我猜你想以一种以后可以通过属性(名称或 ID)检索它的方式存储套接字。在这种情况下,我建议使用HashMap,Integer作为它们Socket的键和值。这是,你可以使用map.get(ID);,它会返回你想要的套接字。

您可以尝试使用 HashMap,也许有一个变量来表示当前连接的人数。当有人登录时,请执行以下操作

public class Serer {

    HashMap<Integer, Socket> list = new HashMap<Integer, Socket>();
    static final int maxConnections = 100;
    static int currentConnections = 0;

    public Server() {
        try {
            ServerSocket socket = new ServerSocket(/*port#*/, maxConnections);
        }catch(IOException e) { }
    }

    public void acceptConnections() {
        while(currentConnections < maxConnections) {
            list.put(currentConnections++, serversocket.accept());
        }
    }

    public Socket getSocket(int ID) {
        return list.get(ID);
    }

    public static void main(String[] args) {
        new Server().acceptConnections();
    }

这没有经过测试,我强烈建议将“acceptConnections”放在一个线程中,这样 while 循环就不会阻止您的代码。我没有发现任何异常,但希望这会让您了解使用 aHashMap来保存您的套接字

现在,如果您想向所有套接字发送数据,则需要OutputStream为每个套接字创建一个。我建议创建一个类(例如User.java),然后当有人连接时,创建一个新用户,并将其传递给套接字。

while(true) {
   new User(ss.accept());
}

然后在你的User.java,有一些类似的东西:

public class User {

    ObjectOutputStream out;
    ObjectInputStream in;

    Socket socket;
    public User(Socket socket) {
        this.socket = socket;

        initStream();
        startChat();
    }

    public void initStream() {
        try{
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputSTream(socket.getInputStream());
        }catch(IOException e) { }
    }

    public void startChat() {
        new Thread(new Runnable() {
            public void run() {
                String input;
                try {
                    while((input = (String) in.readObject) != null) {
                        //this loop only triggers when something is retrieved through the input stream

                       Server.sendGlobalMessage(input); //can be done in different ways
                       //The reason why I call this statically from Server.java is because Server.java
                       //is the class that contains the HashMap, but that's up to you of where to put it.
                       //You could make the `HashMap` static, and make the sendGlobalMessage() in User.java
                    }
                }catch(IOException | ClassNotFoundException e) { }
            };).start();
    }

现在最后对于 sendGlobalMessage,您将需要使用一个Iterator,或者您可以将您的 hashmap 转换为一个数组。这段代码假设您不使用HashMapfor 套接字,而是将套接字传递给 User 类,然后使用HashMap来存储用户。(您需要访问输出流)

HashMap<Integer, User> list = new HashMap<Integer, User>();

public static void sendGlobalMessage(String message) {
    for(User user : list.values().toArray(new User[list.size]) {
        try {
            user.out.writeObject(message);
            user.out.flush();
        }catch(IOException | ClassNotFoundException e) { }
    }
}
于 2013-10-21T18:30:42.903 回答