jxse2.6在jdk8下,JxtaMulticastSocket存在的问题

mac2022-06-30  30

JxtaMulticastSocket覆写了java.net.MulticastSocket的bind方法: @Override public void bind(SocketAddress addr) throws SocketException { if (isBound()) { throw new SocketException("Already bound"); } }

 

  要求在JxtaMulticastSocket的构造函数中会调用bind方法,确保构造函数调用时socket没有被绑定,否则抛出SocketException异常 然而JxtaMulticastSocket的基类java.net.MulticastSocket的构造函数在jdk7和jdk8中的处理是不同的   jdk7: public MulticastSocket(SocketAddress bindaddr) throws IOException { super((SocketAddress) null); // Enable SO_REUSEADDR before binding setReuseAddress(true); if (bindaddr != null) { bind(bindaddr); } }

jdk8:

public MulticastSocket(SocketAddress bindaddr) throws IOException { super((SocketAddress) null); // Enable SO_REUSEADDR before binding setReuseAddress(true); if (bindaddr != null) { try { bind(bindaddr); } finally { if (!isBound()) close(); } } } 可见在jdk8中,如果未绑定,会额外调用close()方法,就是这个close()方法导致抛出了异常 其实在这里不能调用close()方法,从代码上看JxtaMulticastSocket在实现的时候要求此时不能绑定(见其覆写的bind方法) 而close方法也被JxtaMulticastSocket覆写了 /** * Closes this MutlicastSocket. */ @Override public synchronized void close() { if (closed) { return; } bound = false; closed = true; in.close(); outputPipe.close(); in = null; }

此时in尚未初始化,故in.close()会导致java.lang.NullPointerException异常

————————————

1 简单的话,可以修改JxtaMulticastSocket的构造函数,使其不再调用父类的构造函数以避免close()问题(父类构造函数中的相关代码要在子类中重新实现一遍)。2 或者不修改JxtaMulticastSocket的源码,我们干脆自己实现一个子类,提供自己的构造函数初始化代码。

3 较好的方式那就要全面考虑JxtaMulticastSocket的实现了,那就比较复杂了

 ————————————————————————

。。。

1和2现在看起来不大现实,因为父类java.net.MulticastSocket最终都调用了如下构造方法:

/** * Create a MulticastSocket bound to the specified socket address. * <p> * Or, if the address is {@code null}, create an unbound socket. * * <p>If there is a security manager, * its {@code checkListen} method is first called * with the SocketAddress port as its argument to ensure the operation is allowed. * This could result in a SecurityException. * <p> * When the socket is created the * {@link DatagramSocket#setReuseAddress(boolean)} method is * called to enable the SO_REUSEADDR socket option. * * @param bindaddr Socket address to bind to, or {@code null} for * an unbound socket. * @exception IOException if an I/O exception occurs * while creating the MulticastSocket * @exception SecurityException if a security manager exists and its * {@code checkListen} method doesn't allow the operation. * @see SecurityManager#checkListen * @see java.net.DatagramSocket#setReuseAddress(boolean) * * @since 1.4 */ public MulticastSocket(SocketAddress bindaddr) throws IOException { super((SocketAddress) null); // Enable SO_REUSEADDR before binding setReuseAddress(true); if (bindaddr != null) { try { bind(bindaddr); } finally { if (!isBound()) close(); } } }

这意味着子类无论直接还是间接,最终都要调用到这个方法,故close()难以避免的啊!

那就只有修改JxtaMulticastSocket覆写的close()方法了,原close()方法:

/** * Closes this MutlicastSocket. */ @Override public synchronized void close() { if (closed) { return; } bound = false; closed = true; in.close(); outputPipe.close(); in = null; }

修改后:如果尚未绑定的话,close()不执行任何操作

/** * Closes this MutlicastSocket. */ @Override public synchronized void close() { // modified by cuizhf, 20131126 // @see http://www.cnblogs.com/cuizhf/admin/EditPosts.aspx?postid=3443599 if(!bound) { return; } if (closed) { return; } bound = false; closed = true; in.close(); outputPipe.close(); in = null; }

或者这样写:

/** * Closes this MutlicastSocket. */ @Override public synchronized void close() { // modified by cuizhf, 20131126 // @see http://www.cnblogs.com/cuizhf/admin/EditPosts.aspx?postid=3443599 if (!bound || closed) { return; } bound = false; closed = true; in.close(); outputPipe.close(); in = null; }

虽然不是很优雅,至少应该能解决眼前的问题。(实话说Jxse的代码确实算不上优雅)

 ————————————————————————————————————————————————————————

另外一种修改方式就是将java.net.MulticastSocket单独从JDK中提出到在自己的工程中,然后按自己的需要修改(在构造函数中去掉close()的调用),最后使JxtaMulticastSocket继承自修改后的这个类。

 

       ————————————————————————————————————————————————————————— 好吧,从今天开始,secondegg项目的开发全面转向JDK8(JavaFX8)。

转载于:https://www.cnblogs.com/cuizhf/p/3443599.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)