并发线程读取套接字

时间:2014-05-31 00:25:42

标签: java multithreading sockets

我有一个简单的服务器 - 客户端套接字连接。我将所有数据封装在通过ObjectStreams发送的套接字之间前后发送的对象中。

我创造了一个" HeartBeat"监视器,在一个单独的线程中运行,服务器和客户端,每500毫秒,向后和向前发送一个HeartBeat(空对象)以检查连接,这很好。但是,正因如此,当我想在服务器和客户端之间发送其他数据时,它与这些HeartBeat对象混合在一起。

例如,我的服务器需要一个Login对象,而是获取一个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. 放弃HeartBeat功能,虽然似乎没有其他可靠的方法来检查连接状态。
  2. 找一些其他类型的Socket实现,它会为我神奇地修复所有这些。
  3. 有一个同步的方法来监督对套接字的所有读写操作,这会丢弃HeartBeats并将其他对象发送到他们原本想要的位置。
  4. 某种同步魔法。
  5. 提前感谢您的帮助!

    修改 读取Login对象的代码(服务器端):

    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 个答案:

答案 0 :(得分:0)

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

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?
    }
}