0

私がやろうとしているのは、クライアント - >サーバーからメッセージを送信し、サーバーに接続されている他のすべてのクライアントに送り返すことです(マルチスレッド)。異なるクライアントからサーバーへの送信は正常に機能しますが、送信しようとしても何も起こりません。

誰かが接続するたびに、User[] 配列に新しいオブジェクトが作成されます。これにより、各ユーザーの出力ストリームをトリガーできます (User には入力ストリームと出力ストリームの両方を含む Stream オブジェクトが含まれているため、新しい User オブジェクトが作成されるたびに、新しいストリームも作成されます)。

これにより、ユーザー配列内の他のすべてのユーザーに戻ってきたメッセージを送信しようとしています (== null ではありません)。

問題は、メッセージを送り返す部分に到達すると、 User[] 配列内のすべてのユーザーが「null」に戻ることです。

サーバー.java:

package Main;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ForkJoinPool;

import Streams.Stream;

public class Server {
    public static final int maxConnections = 10;

    ServerSocket serverSocket; Socket socket;
    ForkJoinPool pool = new ForkJoinPool();

    static User[] users = new User[maxConnections];

    public Server() {
        try {
            serverSocket = new ServerSocket(43594);

            while(Stream.streams < maxConnections) {
                socket = serverSocket.accept();

                for(User user : users) {
                    if(user == null) {
                        user = new User(socket);
                        System.out.println(user +", 1");
                        pool.execute(user);
                        System.out.println("Someone has joined the chat!");
                        break;
                    } else {
                        System.out.println("Connection declined. Too many users.");
                        break;
                    }
                }
            }           
        }catch(IOException e) { e.printStackTrace(); }
    }

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

ユーザー.java:

package Main;

import java.io.IOException;
import java.net.Socket;

import Streams.Stream;

public class User implements Runnable {

    Stream stream;


    public User(Socket socket) {
        stream = new Stream(socket);

    }

    public void run() {
        String textInput, textOutput;

        while(stream.exists()) {
            try{
                textInput = (String) stream.recieveData();
                sendGlobalMessage(textInput);

            }catch(IOException  e) {
                e.printStackTrace();
            }catch(ClassNotFoundException e) { e.printStackTrace(); }
        }

        stream.close();
    }

    public void sendMessage(String message) throws IOException {
        stream.sendData(message);
    }
    public void sendGlobalMessage(String message) throws IOException {
        for(User user : Server.users) {
            if(user == null) {
                System.out.println(message);
            }else{
                user.sendMessage(message);
            }
        }
    }

}

ストリーム.java:

package Streams;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class Stream {
    public static int streams = 0;

    Socket socket;

    ObjectInputStream input; ObjectOutputStream output;
    Object data;

    public Stream(Socket userSocket) {
        streams++;
        socket = userSocket;

        try{
            input = new ObjectInputStream(userSocket.getInputStream());
            output = new ObjectOutputStream(userSocket.getOutputStream());
        }catch(IOException e) { e.printStackTrace(); }

    }

    public void sendData(Object data) throws IOException {
        output.writeObject(data);
        output.flush();
    }

    public Object recieveData() throws IOException, ClassNotFoundException {
        return data = input.readObject();
    }


    public boolean exists() {
        if(socket.isClosed()) return false; else return true;
    }

    public void close() {
        try {
            input.close();
            output.close();
            socket.close();
        }catch(IOException e) { e.printStackTrace(); }
    }

}

サーバーの構造と関係があるかどうかはわかりません。私にはかなり問題ないように見えますが、なぜこれを行うのか本当にわかりません。

4

2 に答える 2

4

ここUserにある参照は、実際の参照ではなく、配列内の参照のコピーです。

for(User user : users) {
     if(user == null) {
          user = new User(socket);

と同等です

 User user = user[i];

参照を変更しても参照userは変更されませんuser[i]

配列の要素を初期化 (または参照) するには、インデックス付きの for ループを使用する必要があります。

for (int i = 0; i <users.lenght; i++) {
    if(users[i] == null) {
        users[i] = new User(socket);
    } ...
    ...
}
于 2013-09-07T19:18:16.153 に答える
2

for-each ループを使用してリストまたは配列内の項目を初期化することはできません。代わりに、標準の for ループを使用する必要があります。for-each ループでは、オブジェクトを一時変数に割り当てますが、これはリスト項目自体には影響しません。

于 2013-09-07T19:17:08.193 に答える