有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java并发线程读取socket

我有一个简单的服务器-客户端socket连接。我将所有数据封装在对象中,这些对象通过ObjectStreams在socket之间来回发送

我创建了一个“HeartBeat”监视器,它在一个单独的线程中运行,服务器和客户机每500毫秒都会前后发送一个HeartBeat(空对象),以检查连接,这非常有效。然而,正因为如此,当我想在服务器和客户机之间发送其他数据时,它与这些HeartBeat对象混淆了

例如,我的服务器需要一个登录对象,但却得到了一个实例HeartBeat的对象

我的代码是一个简单的客户机/服务器设置,因此我认为没有必要发布他们的代码,但是,心跳代码如下所示:

private static final int HEARTBEAT_INTERVAL = 500;

private void addHeartBeatMonitor(final Socket socket) {
    this.heartBeatTimer = new Timer();
    this.heartBeatTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            try {
                ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
                os.writeObject(new HeartBeat());
                ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
                if (!(is.readObject() instanceof HeartBeat)) { throw new IOException(); }
            } catch (IOException e) {
                LOG.info("Received disconnect from " + getClientSocket().getInetAddress());
                heartBeatTimer.cancel();
                if (clientSocket != null) {
                    try {
                        clientSocket.close();
                    } catch (IOException e1) {}
                }
            } catch (ClassNotFoundException e) {}
        }
    }, 0, HEARTBEAT_INTERVAL);
}

我的选择似乎如下:

  1. 放弃心跳功能,尽管似乎没有其他可靠的方法来检查连接状态
  2. 找到其他类型的socket实现,它将神奇地为我解决所有这些问题
  3. 有一个同步的方法来监督对socket的所有读写,它会丢弃心跳并将其他对象发送到它们应该在的地方
  4. 某种同步魔法

提前感谢您的帮助

编辑: 读取登录对象(服务器端)的代码:

User result = null;
try {
    ObjectInputStream is = new ObjectInputStream(this.getInputStream());
    Login request = (Login) is.readObject(); ### ERROR ###
    result = this.mongoService.login(request);
    ObjectOutputStream os = new ObjectOutputStream(this.getOutputStream());
    os.writeObject(result);
} catch (IOException e) {
} catch (ClassNotFoundException e) {}
return result;

例外情况如下:

Exception in thread "Thread-0" java.lang.ClassCastException: model.HeartBeat cannot be cast to model.Login
    at socket.SocketServerWorker.login(SocketServerWorker.java:78)
    at socket.SocketServerWorker.<init>(SocketServerWorker.java:47)
    at socket.SocketServer$2.run(SocketServer.java:50)
    at java.lang.Thread.run(Thread.java:744)

共 (1) 个答案

  1. # 1 楼答案

    考虑做这样的事情。我只是把它放在一起,所以它显然没有经过测试,但我相信你会明白的:

    public class HeartBeatMonitor
    {
        final Map<Class,Consumer> handlers = new HashMap<> ();
        final Socket sock;
        final ObjectInputStream is;
        final ObjectOutputStream os;
    
        public HeartBeatMonitor (final Socket sock)
        {
            try
            {
                this.sock = sock;
                this.is = new ObjectInputStream (sock.getInputStream ());
                this.os = new ObjectOutputStream (sock.getOutputStream ());
            }
            catch (final IOException e)
            {
                throw new RuntimeException (e);
            }
        }
    
        public <T> void setHandler (final Class<T> type, final Consumer<? super T> handler)
        {
            this.handlers.put (type, handler);
        }
    
        // This would be called in a loop
        void accept () throws ClassNotFoundException, IOException
        {
            final Object o = this.is.readObject ();
            final Consumer handler = this.handlers.get (o.getClass ());
            if (handler != null)
                handler.accept (o);
            // Else default handler?
        }
    }