Kajal
Kajal

Reputation: 739

Socket Closed Exception in SocketImpl Setoption

I am trying to set the SO_KEEPALIVE time of socket.

I created a class SocketBuilder to build the socket instance with SocketImpl. Source code is below,

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();
        }
    }
}

I am getting java.net.SocketException: Socket Closed exception. If I remove the line si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60)); it works fine. But I want to set the SocketImpl.SO_KEEPALIVE. How can I set the SO_KEEPALIVE of socket?

Upvotes: 0

Views: 282

Answers (2)

prasanth
prasanth

Reputation: 3602

If you look at the source code of AbstractPlainSocketImpl#setOption method,

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

You can see there is a isClosedOrPending check before setting the options.

 /*
 * 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;
        }
    }
}

In your case, since you are just creating a socket, it will not have any fd associated with it. That is why you are getting this error.

Upvotes: 0

Yu Jiaao
Yu Jiaao

Reputation: 4714

There some errors in your code:

  1. SocketImpl si = null; this declaration overlap your class field

  2. setOption works only when a socket open/connected

  3. You must close socket when you finish

    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();
        }
    }
    

    }

Upvotes: 1

Related Questions