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 をスローしている場合は、 が であることを意味するだけconnectionsですnullconnectionsそして、一見すると、null 以外の値に初期化されているようには見えません!

修正は、接続を初期化することです...どこか...適切なサイズの配列に。ただし、それは他の問題を引き起こします。配列の適切なサイズidconnections.length?

根本的な問題は、接続を保持するための配列が (おそらく) 不適切な選択であるということです...

于 2013-10-21T18:28:26.920 に答える
1

ソケットが閉じているか、配列のインデックスiが null である可能性があります。List<OutputStream>Socket[]

List<OutputStream>または、データを送信するたびList<OutputStreamWriter>に を初期化する必要はありません。OutputStreamWriter

于 2013-10-21T18:28:22.753 に答える
0

編集:Socket[] array = new Socket[#];

配列を初期化することはありません。それが問題かもしれません。ただし、 aListまたは a のいずれかを使用することをお勧めしますMap。どうやら、ソケットを後でプロパティ (名前または ID) で取得できるように格納したいと思われます。この場合、 をキーとして、値として をHashMap使用することをお勧めします。これは、使用でき、必要なソケットを返します。IntegerSocketmap.get(ID);

HashMap を使用してみてください。おそらく、現在接続している人数の var を使用できます。誰かがログインしたら、次のようにします

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 ループがコードを保持しなくなります。例外は見つかりませんでしたがHashMap、ソケットを保持するためにa を使用する方法を理解していただければ幸いです。

ここで、すべてのソケットにデータを送信したい場合は、ソケット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このコードは、ソケットに を使用する代わりに、ソケットを 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 に答える
0

どういうわけかクライアントソケットオブジェクトを保存する必要があります。ブロードキャストするときはいつでも、コレクションを反復処理してソケットを取得し、そこから出力ストリームを取得して、ソケットに書き込みます。それは私のために適切に働いています。

于 2013-10-21T18:27:50.330 に答える