简体   繁体   English

并发线程读取套接字

[英]Concurrent Threads Reading a Socket

I have a simple Server-Client socket connection. 我有一个简单的服务器-客户端套接字连接。 I encapsulate all my data in objects which are sent backward and forward between the sockets, sent through ObjectStreams. 我将所有数据封装在通过ObjectStreams在套接字之间来回发送的对象中。

I have created a "HeartBeat" monitor, which runs in a separate thread, where both the server and the client, every 500ms, send a HeartBeat (empty object) backward and forward to check for connectivity, which works great. 我创建了一个“ HeartBeat”监视器,该监视器在单独的线程中运行,服务器和客户端每500ms前后发送一个HeartBeat(空对象)以检查连接性,效果很好。 However, because of this, when I want to send other data between the server and client, it is mixed up with these HeartBeat objects. 但是,因此,当我要在服务器和客户端之间发送其他数据时,它与这些HeartBeat对象混合在一起。

For example my Server is expecting a Login object, but instead gets an object of instance HeartBeat. 例如,我的服务器期望使用Login对象,但获取实例HeartBeat的对象。

My code is a simple client/server setup, so I don't think it'd be necessary to post their code, however, the HeartBeat code is as follows: 我的代码是一个简单的客户端/服务器设置,因此我认为不必发布他们的代码,但是,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);
}

My options seem to be to as follows: 我的选择似乎如下:

  1. Ditch the HeartBeat functionality, although there seems to be no other reliable way to check the connection status. 放弃HeartBeat功能,尽管似乎没有其他可靠的方法可以检查连接状态。
  2. Find some other kind of Socket implementation which will magically fix all of this for me. 查找其他类型的Socket实现,它将为我神奇地解决所有这些问题。
  3. Have a synchronized method which oversees all reads and writes to the socket, which discards HeartBeats and sends other objects where they're meant to be. 有一个同步方法,该方法可以监视对套接字的所有读取和写入操作,该方法将丢弃HeartBeats并将其他对象发送到预期的位置。
  4. Some kind of synchronization magic. 某种同步魔术。

Thanks in advance for any help! 在此先感谢您的帮助!

EDIT: Code which reads the Login object (server side): 编辑:读取登录对象(服务器端)的代码:

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 as follows: 异常如下:

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)

Consider doing something like this. 考虑做这样的事情。 I just threw this together, so it's obviously untested, but I'm sure you'll get the idea: 我只是将它们放在一起,因此显然未经测试,但是我敢肯定您会明白的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM