【问题标题】:Continuously read objects from an ObjectInputStream in Java从 Java 中的 ObjectInputStream 连续读取对象
【发布时间】:2015-04-30 11:17:09
【问题描述】:

我在使用 ObjectInputStream 时遇到了问题,我已经为此苦苦挣扎了 2 天。我试图寻找解决方案,但不幸的是没有找到合适的答案。

我正在尝试编写一个客户端/服务器应用程序,其中客户端将对象(在本例中为配置类)发送到服务器。这个想法是连接在发送对象后保持活动状态,因此可以在必要时发送新对象。

以下是我的客户端代码的重要部分:

mSocket = new Socket("192.168.43.56", 1234);

mObjectIn = new ObjectInputStream(mSocket.getInputStream());
mObjectOut = new ObjectOutputStream(mSocket.getOutputStream());

mObjectOut.writeObject(stubConfig);
mObjectOut.flush();

在上面的代码中,我省略了一些 try/catch 块,以保持代码对您的可读性。

服务器端如下:

mHostServer = new ServerSocket(port);
mSocket = mHostServer.accept();

// create streams in reverse oreder
mObjectOut = new ObjectOutputStream(mConnection.getOutputStream());
mObjectOut.flush();
mObjectIn = new ObjectInputStream(mConnection.getInputStream());

while (mIsSocketConnected)
{
    StubConfig = (StubConfiguration)mObjectIn.readObject(); 
}

我想要实现的是,只要 socketconnection 处于活动状态,服务器就会监听传入的配置对象。

但是,当我运行我的程序时,我在服务器端的 while 循环中遇到了 EOFException。我在 while 循环的第一次迭代中收到了第一个配置对象,没有任何问题,但之后每次调用 readObject() 时我都会收到 EOFException。

我正在寻找解决此问题的方法。任何人都可以把我引向好的方向吗?

编辑:我读到的有关 EOFException 的内容是,当您想从流中读取时,它会在到达它的末尾时被抛出。这意味着由于某种原因,流在对象发送后结束。有没有办法重新初始化流??

【问题讨论】:

  • 您在第二次迭代中有一个 EOF,因为客户端写入一次(没有 while),而服务器循环读取。所以用 if 替换 while 读取一次

标签: java sockets networking objectinputstream eofexception


【解决方案1】:

EOFException 在对等方关闭连接时由readObject() 抛出。之后永远不会有更多的数据。 所以你根本不能写多个对象:你关闭了连接。

【讨论】:

  • 这听起来确实是个问题。我没有说我已经发送了多个对象,我只是说我在一个 while 循环中读取它们并且只有第一次迭代是成功的。有没有办法在发送对象后保持连接打开。我没有手动关闭它所以我认为它是自动完成的
  • 不是自动完成的。你把它关了。关闭套接字的输入或输出流会关闭另一个流和套接字。
【解决方案2】:

试试这个

服务器端
1.Server运行在单独的线程上

public class ServeurPresence implements Runnable {

public final static int PORT = 20000 ;
public final static String HOSTNAME = "localhost" ;
public static enum Action {CONNEXION, MSG, DECONNEXION,USER, FINCLASSEMENT};

ServerSocket serveur ;
static List<String> names ;

 */
public ServeurPresence() 
{

    System.out.println("Start Server...");
    try 
    {
        serveur = new ServerSocket(PORT) ;
        new Thread(this).start();
        //javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() {   createAndShowGUI();}    }   );
    } 
    catch (IOException e)
    {
        e.printStackTrace();
    }
}
/**
 * @param args
 */
public static void main(String[] args)
{
    new ServeurPresence();

}
@Override
public void run() 
{
    System.out.println("server runs");

        while(true)
        {
            try {

                Socket sock = serveur.accept();
                ServiceClientsThread thread= new ServiceClientsThread(sock);
                thread.start();

            }
            catch (IOException e) 
            {
                System.out.println("Error with  socket");
                e.printStackTrace();        
            }
        }

}

}


2.一个Thread来处理每个Client:ServiceClientThread

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;


 public class ServiceClientsThread extends Thread{
    private Socket sock ;
ServiceClientsThread(Socket sock)
{
        //super();
        this.sock=sock;
}

@Override
public void run() 
{
    DataInputStream is ;
    DataOutputStream os ;
    String name =null ;

    try {

        is = new DataInputStream(sock.getInputStream()) ;
        os = new DataOutputStream(sock.getOutputStream()) ;
        ServeurPresence.Action act ;

        do {
            // read Action              
            act = ServeurPresence.Action.valueOf(is.readUTF()) ; // read string -> enum
            System.out.println("action :"+act);
            switch (act) {

            case CONNEXION :
                name = is.readUTF(); //read client name
                System.out.println("Name :"+name);
                os.writeUTF("Hi");//send welcome msg
                break ;
            case MSG :
                String msg = is.readUTF();
                 os.writeUTF("OK");//response
                break ;
            case DECONNEXION :
                System.out.println(name+" is logged out");
                break ;
            }

        } while (act!=ServeurPresence.Action.DECONNEXION) ;

        // the end
        is.close();
        os.close();
        sock.close();

    } catch (IOException e) 
    {
        System.out.println("Error with "+name+" socket");
        e.printStackTrace();        
    }
}

}


3.客户端

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;


public class Client {
/**
 * 
 */
Client(String name)
{
    System.out.println("Start Client...");

    try {

        Socket sock = new Socket(ServeurPresence.HOSTNAME,ServeurPresence.PORT) ;
        DataOutputStream os = new DataOutputStream(sock.getOutputStream()) ;
        DataInputStream is = new DataInputStream(sock.getInputStream()) ;

                    System.out.println("Send "+name+" to server");

        // CONNECTION : Action then value
        os.writeUTF(ServeurPresence.Action.CONNEXION.name()) ; // send action : write enum -> String
        os.writeUTF(name) ; // send the name

                    //read server welcome msg
        String msg = is.readUTF();
                    System.out.println("Welcome msg: "+msg);

        /*  Your actions here : see example below */
        try 
        {
            Thread.currentThread().sleep(4000);
            os.writeUTF(ServeurPresence.Action.MSG.name()) ; // send action : write enum -> String
            os.writeUTF("My message here") ; // send msg
            Thread.currentThread().sleep(4000);
            msg = is.readUTF();//server response message
        } 
        catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
        /************************************************/

        //CLOSE
        os.writeUTF(ServeurPresence.Action.DECONNEXION.name()) ; // send action
        System.out.println("Log out");
        os.close();
        sock.close();

    }
    catch (UnknownHostException e) 
    {
        System.out.println(ServeurPresence.HOSTNAME+ " unknown");
        e.printStackTrace();
    } 
    catch (IOException e)
    {
        System.out.println("Impossible to connect to "+ServeurPresence.HOSTNAME+ ":"+ServeurPresence.PORT);
        e.printStackTrace();
    } 
}

}


4. 在您​​的情况下,使用 readObject()/writeObject() 而不是 readUTF()/writeUTF() 来编写您的配置对象

【讨论】:

  • 试试看,为什么?这如何回答这个问题?
  • 您好 DAO,感谢您的反应。不幸的是,它没有帮助。您能否向我解释一下您认为这里的问题是什么以及为什么您的解决方案可以帮助解决它?
  • @MarvinLasut 如果没有帮助,您为什么将此答案标记为正确?
  • @DAO 更改为数据输入/输出流并添加更多数据类型来传输实际上并不能解决问题,也不是对原始代码的任何改进。对于相同的结果,它只是复杂十倍。它甚至不是好的代码。睡眠实际上是在浪费时间,而Thread.sleep() 是一个静态方法,所以调用currentThread() 也是没有意义的。 (4) 如果您删除对象流,则不可能适用。
  • 我举了一个例子,说明如何在双方同步读写,因为在他的代码中,他试图读取许多对象,而只有一个写入对象(来自客户端)。这就是为什么我建议在客户端稍后发送另一个对象或想要注销的情况下枚举操作。
【解决方案3】:

试试这个,让我知道结果如何:

while (1==1)
{
    StubConfig = (StubConfiguration)mObjectIn.readObject();
    Thread.sleep(100); //Saves CPU usage
}

【讨论】:

  • 不,它不会节省 CPU 使用率。只是浪费时间和空间。读取将阻塞,直到数据到达。
  • 您好 zhalla,感谢您的反应。不幸的是,它没有帮助。
  • @EJP 在这种情况下如何节省 CPU 使用率?
  • @zhalla 节省什么 CPU 使用率? read() 中的代码块直到数据到达。没有可节省的 CPU 使用率。
  • 哦,我不知道。谢谢解释
【解决方案4】:

答案很晚,但仅供将来参考。我一直在通过套接字发送对象时遇到问题,因为 flush() 方法无法正常工作。

我只是通过将flush() 切换为reset() 解决了这个问题。

【讨论】:

  • 方法flush() 确实可以正常工作,如果您通过调用reset() 解决了您的问题,那么您遇到了不同的问题,而不是这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 2013-07-07
  • 2014-05-30
相关资源
最近更新 更多