【问题标题】:Streams - ObjectOutputStream gives NULL流 - ObjectOutputStream 给出 NULL
【发布时间】:2013-02-04 09:17:45
【问题描述】:

我有两个可以相互配合使用的应用程序。一种是“服务器”类型的应用程序,它没有任何 GUI 界面并处理对数据库的查询并处理来自客户端的请求。另一个是“客户端”,主要是一个 GUI,供用户以结构化方式与数据库信息进行交互。

问题/麻烦/需要帮助

我遇到的问题是我可以成功地将一个对象(一个字符串 [])发送到服务器并且没有问题。客户端应用程序发送它,服务器应用程序接收它并成功处理它。

如果我尝试发送第二个 String[],客户端编译数组并认为它已发送,但服务器从未收到 is(仅获取 null)并产生 IOException。

即使数组包含完全相同的位置数和完全相同的格式和位置的完全相同的文本。

printStackTrace() 产生的错误是:

Java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1367)
at java.io.ObjectInputStream.readObject (ObjectInputStream.java:369)
at server.ConnectionThread.processClientRequests(ConnectionThread:204)
at server.ConnectionThread.processClientRequests(ConnectionThread:50)
at javalang.Thread.run(Thread.java:722) 

第 204 行的代码是读取 ObjectStream 的位置:

String[] addArray = (String[]) ois.readObject();

ois是一个ObjectInputStream,初始化如下:

private ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

客户代码

用于将这些对象发送到服务器应用程序的客户端代码是:

ObjectToServer.writeObject(String[] var);
ObjectToServer.flush();
ObjectToServer.reset();

评论

对我来说没有意义的是,这种完全相同的代码格式用于通过 objectOutputStream 从 SERVER 成功发送多个 String[] 到 CLIENT 应用程序,而无需发送“null”

我已经用谷歌搜索了这个,但完全无济于事。

如果可以,请有人帮忙!

                             ADDITIONAL CODE

// CONNECTION THREAD IS ON SERVER APP, SETS UP STREAMS AND WAITS FOR MESSAGES FROM CLIENT
// HANDLES COMMUNICATION FROM CLIENT AND REST OF SERVER

public class ConnectionThread implements Runnable
{

    private Socket socket;
    private SystemCore core;
    //Streams for connections
    private InputStream is;
    private OutputStream os;
    //Writers and readers for communication of Strings
    private PrintWriter toClient;
    private BufferedReader fromClient;
    // Writers and readers for sending and receiving Objects between server and client.
    private ObjectInputStream ois = null;
    private ObjectOutputStream oos = null;
    //Protocol
    static final String CLIENT_QUITTING = "Exit";

    public ConnectionThread(Socket s, SystemCore aSysCore)
    {
        socket = s;

        // State of the SystemCore as taken from HelloServer
        core = aSysCore;
    }

    public void run()
    {
        try
        {
            openStreams();
            toClient.println(MESSAGE_TO_CLIENT);
            processClientRequests();
            closeStreams();
            this.socket.close();
        }
        catch (OptionalDataException ode )
        {
            System.out.println("OptionalDataException: ");
            System.out.println("length is: " + ode.length);
        }
        catch (IOException ioe)
        {
            System.out.println("IO trouble with a connection in ConnectionThread run() " + ioe.getMessage());
            ioe.printStackTrace();
        }
       catch (ClassNotFoundException cnf)
        {
            System.out.println("Class trouble with a connection in ConnectionThread run() " + cnf.getMessage());
            cnf.printStackTrace();
        }
        catch(ParseException pe)
        {
            System.out.println("Parse trouble with a connection in ConnectionThread run() " + pe.getMessage());
            pe.printStackTrace();
        } 
    }

    /**
     * Opens streams between the server and the client.
     *
     * @throws IOException
     */
    private void openStreams() throws IOException
    {
        final boolean AUTO_FLUSH = true;
        this.is = this.socket.getInputStream();
        this.fromClient = new BufferedReader(new InputStreamReader(is));
        this.os = this.socket.getOutputStream();
        this.toClient = new PrintWriter(os, AUTO_FLUSH);

        //Object streams.
        oos = new ObjectOutputStream(socket.getOutputStream());
        ois = new ObjectInputStream(socket.getInputStream());

        System.out.println("...Streams set up");
    }


    /**
     * Private method that accepts arguments from a client and executes the related
     * commands in the systemcore as long as the command passed from the client
     * is not CLIENT_QUITTING.
     *
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void processClientRequests() throws IOException, ClassNotFoundException, ParseException
    {
        String commandFromClient;
        commandFromClient = fromClient.readLine();
        while (!(commandFromClient.equals(CLIENT_QUITTING)))
        {
            if (commandFromClient.equals("addProjectPrepare"))
            {
                String[] addArray = (String[]) ois.readObject();
                core.addProjectPrepare(addArray);
            }
            if (commandFromClient.equals("editProjectPrepareDetails"))
            {
                String[] editArray = (String[]) ois.readObject();
                recruit.editProjectPrepareDetails(editArray);               
            }
        }
           commandFromClient = fromClient.readLine();
    }


**// CLIENT SIDE (User GUI) CODE THAT SENDS STRING[] TO THE SERVER**




public void saveAction()
    {
        // TEST TO SEE IF THE DATE ENTERED IS CORRECT FORMAT, IF NOT NO SAVE OCCURRS

    boolean parsedOk = false;

    if (this.arrivalDateTextField.getText().isEmpty() == false)
    {
        try
        {
            // Check if date is correct format. Nothing will be done with 
            // the testDate object

            MyDate testDate = new MyDate(
                    this.arrivalDateTextField.getText());

            //Allow write to server to occur.
            parsedOk = true;
            //If date is okay, send form data to server.
        }
        catch (ParseException pe)
        {
            this.arrivalDateTextField.setText(""); // Set text field to blank
            int messageIcon = javax.swing.JOptionPane.ERROR_MESSAGE;
            JOptionPane.showMessageDialog(this, "Invalid date",
                    "Warning", messageIcon);
        }
    }
    else
    {
        parsedOk = true; // No date entered so allow blank. 
    }
    if (parsedOk == true)
    {
        // WRITE DATA TO SERVER OCCURS HERE: 

        try
        {

            **//getPersonDetails() returns a String[]**

            ManageClientConnections.toServer.println("addNewData");                 
       ManageClientConnections.objectToServer.writeObject(this.getPersonDetails());
            ManageClientConnections.objectToServer.flush();
            ManageClientConnections.objectToServer.reset();
        }
        catch (IOException ioe)
        {
            System.out.println(
                    "While writing new person to server, there was an error: " + ioe.getMessage());
        }

        // And dispose of the GUI, inside the parseok if clause
        this.dispose();
    }
}

【问题讨论】:

  • 你能抓住OptionalDataException 并打印出exception.length 字段吗?另外,上面的评论。
  • 为什么要重置输出流?
  • 感谢 Pescis 和 jtahlborn - 我添加了适用的附加代码。 @Pecsis - 在 OptionalDataException 的 exception.length 上,长度为 0。 Fildor - 我重置了输出流,因为我有一个打开的流并一遍又一遍地向它写入对象。根据我阅读的内容(不久前),我需要重置 ObjectOutputStream 否则会出现持续错误。
  • "服务器永远不会收到 is (只得到 null) 并产生一个 IOException。"不,它会抛出一个IOException 而不是 产生任何东西。任何空值都由您的代码生成。
  • @Fildor 如果您不知道ObjectOutputStream.reset() 的作用,请查一下。 OP在这里做的事情并不奇怪。

标签: java ioexception objectoutputstream objectinputstream


【解决方案1】:

您不能在同一个套接字输入/输出流上创建多个输入/输出流。那是行不通的。你需要选择一种类型的流并坚持下去。由于您需要发送结构化数据,您应该使用 Object 流并放弃 Print 流。如果您需要从客户端向服务器发送不同类型的消息,那么您应该考虑使用可包含不同类型消息的包装 Serializable 对象类型(例如 Message)。

【讨论】:

  • 但它是一个流,其中写入了多个对象,然后刷新和重置——而不是多个。并且将多个对象写入从服务器应用程序到客户端应用程序的单个流确实有效。
  • @joelBeaton - 嗯?您的 openStreams 方法在 same 套接字 InputStream 之上创建了一个 BufferedReader 和 ObjectInputStream。
  • 是的,其中一个 (BufferedReader) 处理客户端应用程序中的 PrintWriter 写入它的字符串,而另一个 (ObjectInputStream) 处理来自客户端的传入对象。这是不允许的吗?我应该创建两个套接字对象并拆分此流量吗?
  • @joelBeaton - 在我的回答中已经回答了所有这些问题。
  • 好的,我会调整所有这些,然后再回来告诉你进展如何。
猜你喜欢
  • 1970-01-01
  • 2018-11-06
  • 2016-01-29
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 2018-01-30
相关资源
最近更新 更多