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 保存 Object 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_list发送ObjectOutputStream 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();

在这里,私有ObjectInputStream 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

看起来您正在使用同一流的流和修饰版本。因为有一些缓冲正在进行,所以这不起作用。坚持只使用一个装饰实例。

于 2011-09-06T22:34:02.437 回答
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 回答
0

您假设您“必须使用序列化”。序列化当然是这里的一种选择,但肯定不是唯一的选择。

序列化有几个缺点:

  • 特定于 Java
  • 复杂 - 序列化是 Java 语言更高级的特性之一
  • 重构很棘手(如果您不能总是同时升级客户端和服务器,那么对同样序列化的类进行更改可能会很棘手)
  • 难以调试(如果出现问题,您无法手动检查“通过网络”发生的情况并查看是否正确)

使用另一种为客户端-服务器通信设计的编码(想到 JSON)可能值得考虑。

(I know it is annoying when you ask a question "how do I do foo with X" and people respond with "don't use X, use Y!", but it seems like you might want to consider this...)

于 2011-09-06T23:19:01.973 回答