1

こんにちは、プライベートメッセージの送信、オンラインリストの表示などの特別な機能を含むクライアントサーバープログラムに取り組んでいるので、シリアライゼーションを使用する必要があることを知っており、最初にそれを管理しましたが、しばらくするとめちゃくちゃになりました:)シリアル化することを学びます。複雑さを避けるために、意味のある部分のみを共有します。どこが間違っているのか知りたいです。とにかくあなたの助けに感謝します。これはサーバー コードの一部です。

    public class Server {

        private ServerSocket ss;
        private Socket socket;
        private Map<Socket,DataOutputStream> list = new HashMap<Socket,DataOutputStream>();
        private LinkedList<Person> client_list = new LinkedList<Person>();
        private String socketName;
        private Object lockObj = new Object();

        public Server(int port_number) throws IOException{

            create_Server(port_number);
        }

        public static void main(String[] args) throws IOException {

            int port_number=23;

            new Server(port_number);
        }

        private void create_Server(int port_number) throws IOException{

            ss = new ServerSocket(port_number);

            System.out.println("Server is ready!");

            while(true){

                socket=ss.accept();

                System.out.println(socket.getLocalAddress().getHostName() + " was connected!");

                send_con_mes();

                list.put(socket,new DataOutputStream(socket.getOutputStream()) );

                ServerThread st = new ServerThread(socket,this);

                Person per = new Person(socket.getInetAddress().toString());

                client_list.add(per);

                st.start();


            }

        }

            public LinkedList<Person> send_list(){  

                   return client_list;
        }

だから私はサーバーを作成し、ソケットの応答を待っています。さらに、ソケットとその出力を保存するために list を使用し、clien_list はオブジェクト person を保存します (person はシリアライズ可能なオブジェクトです)。

ここにサーバースレッドの部分があります

public class ServerThread extends Thread {

    private Socket s;
    private Server srv;
    private String socketName;
    private StringTokenizer str;
    private String message = "";
    private LinkedList<Person> client_list;
    private ObjectOutputStream oos;

    private static int i=0;

    public ServerThread(Socket s,Server srv){
        this.s = s;
        this.srv = srv;

        try {
            oos = new ObjectOutputStream(s.getOutputStream());

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void setList(){

        client_list = srv.send_list();

    }

    private LinkedList<Person> getList(){

        return client_list;
    }

    @Override
    public void run() {

        String msg;
        String token;
        DataInputStream dis;

        try {
            dis = new DataInputStream(s.getInputStream());

            while(true){

                msg = dis.readUTF();
                srv.send_to_All(msg, s);

                setList();

                oos.writeObject(getList());
                oos.flush();

            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                srv.remove_Connection(s);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

だから私は client_listObjectOutputStream oosをクライアントに送信します。

最後に、リストを取得して人物オブジェクトを逆シリアル化し、情報を読み取るクライアント部分です...

public class Client extends javax.swing.JFrame implements Runnable {

    private DataOutputStream dos;
    private DataInputStream dis;
    private Socket s;
    private String Client_name;
    private String Ip_addr;
    private Font font = new Font("Arial", Font.PLAIN, 13);
    private int click_num_b=0;
    private int click_num_i=0;
    private LinkedList<Person> client_list;

    private FileOutputStream fos;
    private PrintStream pts;
    private ObjectInputStream socketIn;

/** Creates new form Client */
public Client() {
    initComponents();
    Screen.setEditable(false);

    Text_Field.setFont(font);
    Screen.setFont(font);
    start_Chat();

}

    @Override
    public void run() {

        try {

            while(true){

                    read_list();

                String message = dis.readUTF();
                Screen.append(message + "\n");

            }

        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    private void read_list() throws IOException{

        socketIn = new ObjectInputStream(s.getInputStream());

        try {

            client_list = (LinkedList<Person>) socketIn.readObject();

            for (Iterator<Person> itr = client_list.iterator(); itr.hasNext();) {

                Person per = itr.next();

                pts.println(per.getnickName() );

            }

            socketIn.close();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void start_Chat() {
        try {

            Ip_addr = JOptionPane.showInputDialog("Enter the IP number of the server to connect : ");
            s = new Socket(Ip_addr, 23);

            Client_name = JOptionPane.showInputDialog("Enter your Nickname : ");

            dis = new DataInputStream(s.getInputStream());         
            dos = new DataOutputStream(s.getOutputStream());

            fos = new FileOutputStream("personList.txt");
            pts = new PrintStream(fos);

            new Thread(Client.this).start();

ここで、privateObjectInputStream socketIn;はシリアライズ可能なオブジェクトを受け取り、ファイルに書き込みます。ここに私が直面しているいくつかのエラーがあります

java.io.EOFException
    at java.io.DataInputStream.readUnsignedShort(Unknown Source)
    at java.io.DataInputStream.readUTF(Unknown Source)
    at java.io.DataInputStream.readUTF(Unknown Source)
    at ServerThread.run(ServerThread.java:58)


SEVERE: null
java.io.StreamCorruptedException: invalid type code: 00
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at Client.read_list(Client.java:81)
    at Client.run(Client.java:61)
    at java.lang.Thread.run(Unknown Source)

この問題を処理するのを手伝っていただければ幸いです。

4

3 に答える 3

1

自分のオブジェクトのみを送信してください。例えば

interface ServerToClientPacket { 
    void performAction(Client c); 
}

class MyMessage implements ServerToClientPacket {
    String message;
    MyMessage(String message) { this.message = message; }
    void performAction(Client c) {
        JOptionPane.showMessageDialog(message);
    }
}

class PersonList implements ServerToClientPacket {
    LinkedList<Person> people;
    // constructor here
    void performAction(Client c) {
        for(Person person : people) {
            c.pts.println(person);
        }
    }
}

それぞれが、シリアル化されたデータを使用してクライアントに独自の performAction を実装します。振る舞いを定義するときは、クライアントではなく、メッセージに入れます。その後、クライアントは、ソケットから渡されたさまざまなメッセージと動作の表示メカニズムにすぎません。

于 2011-09-06T23:00:10.120 に答える
1

ストリームと同じストリームの装飾されたバージョンを使用しているようです。バッファリングが行われているため、これは機能しません。装飾されたインスタンスを 1 つだけ使用するようにしてください。

于 2011-09-06T22:34:02.437 に答える
0

「シリアル化を使用する必要がある」と仮定します。シリアル化は確かにここでのオプションですが、確かに唯一のオプションではありません。

シリアル化にはいくつかの欠点があります。

  • Java 固有
  • 複雑 - シリアル化は、Java 言語のより高度な機能の 1 つです。
  • リファクタリングが難しい (クライアントとサーバーの両方を常に同時にアップグレードできるとは限らない場合、直列化されているクラスを変更するのは難しい場合があります)
  • デバッグが難しい (問題が発生した場合、「回線上」で何が起こっているかを手動で調べて、それが正しいかどうかを確認することはできません)

クライアントとサーバーの通信用に設計された別のエンコーディング (JSON が思い浮かびます) を使用することを検討する価値があるかもしれません。

(「X で foo を実行するにはどうすればよいか」という質問をすると、「X を使用しないで、Y を使用してください!」と答えるのが面倒なのはわかっていますが、これを検討する必要があるようです...)

于 2011-09-06T23:19:01.973 に答える