如何在SocketChannel关闭时收到通知? [英] How to be notified when a SocketChannel is closed?

查看:226
本文介绍了如何在SocketChannel关闭时收到通知?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在 时收到通知SocketChannel 关闭 方法。我的第一个想法是创建一个包装器,当调用 implCloseSelectableChannel 方法时通知监听器(因为 close 方法本身在 AbstractInterruptibleChannel 中声明 final 。这个解决方案有效,但是当我尝试用 Selector 注册它时,我会得到一个 IllegalSelectorException ,因为下面的检查在 SelectorImpl

I want to be notified when a SocketChannel has its close method called. My first thought was to create a wrapper which notifies a listener when the implCloseSelectableChannel method is called (since the close method itself is declared final in AbstractInterruptibleChannel). This solution works, but when I tried to register it with a Selector I would get an IllegalSelectorException because of the following check in SelectorImpl:

/*     */   protected final SelectionKey register(AbstractSelectableChannel paramAbstractSelectableChannel, int paramInt, Object paramObject)
/*     */   {
/* 128 */     if (!(paramAbstractSelectableChannel instanceof SelChImpl))
/* 129 */       throw new IllegalSelectorException();

现在我无法覆盖寄存器委托给包装 SocketChannel 的方法,因为它在 AbstractSelectableChannel final c>我无法实现 SelChImpl ,因为它在 sun.nio.ch 包中具有默认可见性。我可以看到从这里开始的唯一方法是制作我自己的 SelectorProvider 选择器,但这似乎是对于这么简单的事情有点过分。

Now I can't override the register method to delegate to the wrapped SocketChannel because it's declared final in AbstractSelectableChannel and I can't implement SelChImpl because it has default visibility in the sun.nio.ch package. The only way I can see to proceed from here would be to make my own SelectorProvider and Selector, but that seems like overkill for something so simple.

SocketChannel 关闭或做什么时,是否有更简单的方式得到通知我需要重新考虑我的程序设计吗?

Is there an easier way to be notified when a SocketChannel has been closed or do I need to rethink my program design?

SocketChannelWrapper 示例:

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SocketChannelWrapper extends SocketChannel {
    private static interface CloseListener {
        public void socketChannelClosed(SocketChannel channel);
    }

    private final SocketChannel socket;
    private final CloseListener listener;

    public SocketChannelWrapper(SocketChannel socket, CloseListener l) {
        super(socket.provider());
        this.socket = socket;
        listener = l;
    }

    @Override
    public SocketAddress getLocalAddress() throws IOException {
        return socket.getLocalAddress();
    }

    @Override
    public <T> T getOption(SocketOption<T> name) throws IOException {
        return socket.getOption(name);
    }

    @Override
    public Set<SocketOption<?>> supportedOptions() {
        return socket.supportedOptions();
    }

    @Override
    public SocketChannel bind(SocketAddress local) throws IOException {
        return socket.bind(local);
    }

    @Override
    public <T> SocketChannel setOption(SocketOption<T> name, T value)
            throws IOException {
        return socket.setOption(name, value);
    }

    @Override
    public SocketChannel shutdownInput() throws IOException {
        return socket.shutdownInput();
    }

    @Override
    public SocketChannel shutdownOutput() throws IOException {
        return socket.shutdownOutput();
    }

    @Override
    public Socket socket() {
        return socket.socket();
    }

    @Override
    public boolean isConnected() {
        return socket.isConnected();
    }

    @Override
    public boolean isConnectionPending() {
        return socket.isConnectionPending();
    }

    @Override
    public boolean connect(SocketAddress remote) throws IOException {
        return socket.connect(remote);
    }

    @Override
    public boolean finishConnect() throws IOException {
        return socket.finishConnect();
    }

    @Override
    public SocketAddress getRemoteAddress() throws IOException {
        return socket.getRemoteAddress();
    }

    @Override
    public int read(ByteBuffer dst) throws IOException {
        return socket.read(dst);
    }

    @Override
    public long read(ByteBuffer[] dsts, int offset, int length)
            throws IOException {
        return socket.read(dsts, offset, length);
    }

    @Override
    public int write(ByteBuffer src) throws IOException {
        return socket.write(src);
    }

    @Override
    public long write(ByteBuffer[] srcs, int offset, int length)
            throws IOException {
        return socket.write(srcs, offset, length);
    }

    @Override
    protected void implCloseSelectableChannel() throws IOException {
        socket.close();
        listener.socketChannelClosed(this);
    }

    @Override
    protected void implConfigureBlocking(boolean block) throws IOException {
        socket.configureBlocking(block);
    }

    public static void main(String[] args) throws UnknownHostException,
            IOException {
        final Selector selector = Selector.open();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        selector.select();
                        Iterator<SelectionKey> itr = selector.selectedKeys()
                                .iterator();
                        while (itr.hasNext()) {
                            SelectionKey key = itr.next();
                            itr.remove();

                            if (key.isValid()) {
                                if (key.isAcceptable()) {
                                    ((ServerSocketChannel) key.channel())
                                            .accept();
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t.setDaemon(true);

        ServerSocketChannel server = ServerSocketChannel.open().bind(
                new InetSocketAddress(1234));
        server.configureBlocking(false);

        server.register(selector, SelectionKey.OP_ACCEPT);
        t.start();

        SocketChannel socket = new SocketChannelWrapper(
                SocketChannel.open(new InetSocketAddress(InetAddress
                        .getLocalHost(), 1234)), new CloseListener() {
                    @Override
                    public void socketChannelClosed(SocketChannel channel) {
                        System.out.println("Socket closed!");
                    }
                });
        socket.configureBlocking(false);
        // socket.close(); //prints out "Socket closed!"
        socket.register(selector, SelectionKey.OP_READ);
    }
}


推荐答案

如果 SocketChannel 已关闭,您正在关闭它,因此您可以按照自己喜欢的方式通知自己。

If the SocketChannel is closed by you, you are closing it, so you can notify yourself any way you like.

如果您希望在 peer 关闭连接时收到通知 OP_READ 将会触发并且读取将返回 - 1。

If you want to be notified when the peer closes the connection,, OP_READ will fire and a read will return -1.

这篇关于如何在SocketChannel关闭时收到通知?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆