SocketImpl Setoption中的套接字闭合异常

时间:2017-04-06 04:06:41

标签: java sockets

我正在尝试设置套接字的SO_KEEPALIVE时间。

我创建了一个类SocketBuilder来使用SocketImpl构建套接字实例。源代码如下,

public class SocketBuilder {

    private static SocketImpl si;

    public static Socket createCVPSocket() throws Exception {
        if (si == null) {
            init();
        }
        return new CSocket(si);
    }    


    private static void init() throws SocketException {
        @SuppressWarnings("rawtypes")
        Constructor cons = null;
        try {
            cons = Class.forName("java.net.SocksSocketImpl")
                    .getDeclaredConstructor();
        } catch (NoSuchMethodException | SecurityException
                | ClassNotFoundException e) {
            throw new RuntimeException(
                    "Not able to access socket implementation.");
        }
        cons.setAccessible(true);
        SocketImpl si = null;
        try {
            si = (SocketImpl) cons.newInstance();
        } catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException("Not able to create instance of socket.");
        }
        if (si != null) {
            si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60));
        }
    }

    private static class CSocket extends Socket {
        protected CSocket(SocketImpl si) throws SocketException, Exception {
            super(si);
        }
    }
    public static void main(String[] args) {
        try {
            Socket sock = SocketBuilder.createCVPSocket();
            System.out.println(sock);
        } catch (Exception e) { 
            e.printStackTrace();
        }
    }
}

我收到java.net.SocketException: Socket Closed例外。如果我删除行si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60));,它可以正常工作。但我想设置SocketImpl.SO_KEEPALIVE。如何设置套接字SO_KEEPALIVE

2 个答案:

答案 0 :(得分:1)

您的代码中存在一些错误:

  1. SocketImpl si = null;此声明与您的课程字段重叠

  2. setOption仅在套接字打开/连接

  3. 时有效
  4. 完成后必须关闭套接字

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.net.*;
    
    public class SocketBuilder {
    private static SocketImpl si;
    
    public static Socket createCVPSocket() throws Exception {
        if (si == null) {
            init();
        }
        return new CSocket(si);
    }    
    
    
    private static void init() throws SocketException {
        @SuppressWarnings("rawtypes")
        Constructor cons = null;
        try {
            cons = Class.forName("java.net.SocksSocketImpl")
                    .getDeclaredConstructor();
        } catch (NoSuchMethodException | SecurityException
                | ClassNotFoundException e) {
            throw new RuntimeException(
                    "Not able to access socket implementation.");
        }
        cons.setAccessible(true);
        si = null;
        try {
            si = (SocketImpl) cons.newInstance();
        } catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException("Not able to create instance of socket.");
        }
    
    }
    
    private static class CSocket extends Socket {
        protected CSocket(SocketImpl si) throws SocketException, Exception {
            super(si);
            super.bind(new InetSocketAddress("127.0.0.1", 8888));
    
            si.setOption(SocketImpl.SO_KEEPALIVE, Boolean.TRUE);
        }
    }
    public static void main(String[] args) {
        try {
            Socket sock = SocketBuilder.createCVPSocket();
            System.out.println(sock);
        } catch (Exception e) { 
            e.printStackTrace();
        }
    }
    

    }

答案 1 :(得分:0)

如果查看AbstractPlainSocketImpl#setOption方法的源代码,

public void setOption(int opt, Object val) throws SocketException {
        if (isClosedOrPending()) {
            throw new SocketException("Socket Closed");
        }
// Rest of the code removed for brevity
}

在设置选项之前,您可以看到isClosedOrPending检查。

 /*
 * Return true if already closed or close is pending
 */
public boolean isClosedOrPending() {
    /*
     * Lock on fdLock to ensure that we wait if a
     * close is in progress.
     */
    synchronized (fdLock) {
        if (closePending || (fd == null)) {
            return true;
        } else {
            return false;
        }
    }
}

在您的情况下,由于您只是创建一个套接字,它将不会有任何与之关联的fd。这就是你得到这个错误的原因。