WebSocket Secure java.nio.channels.UnresolvedAddressException

时间:2016-10-30 22:16:46

标签: java android websocket

我遇到了使用WebSocket Secure的问题。我使用这个websocket库:'org.java-websocket:Java-WebSocket:1.3.0'。该问题仅出现在LENOVO智能手机上(并非适用于所有型号,例如联想A6000按预期工作)。例如,Lenovo Vibe设备上发生错误。我在Nexus 4,Nexus 5,Nexus 5x,Nexus 6,Nexus 6P,联想A6000,联想Vibe,三星Galaxy SIII(CyanogenMod Android 4.4.4)上进行了测试。此列表中仅在Lenovo Vibe设备上出现错误。 这是一个错误:

java.nio.channels.UnresolvedAddressException

这是我的代码:

    final String url =  wss://*****.com/wss;
    URI uri=null;
    try{
        uri = new URI(url);
    }
    catch (Exception e)
    {
    }
    Map<String, String> headers = new HashMap<>();
    headers.put("auth_key", TOKEN);
    mWebSocketClient = new WebSocketClient(uri, new Draft_10(), headers, 0) {
        @Override
        public void onOpen(ServerHandshake handshakedata) {

        }
        @Override
        public void onMessage(String message) {

        }

        @Override
        public void onClose(int code, String reason, boolean remote) {

        }

        @Override
        public void onError(Exception ex) {
            //HERE I HANDLE AN ERROR ON LENOVO VIBE
        }
    };
    try{
        SSLContext sslContext = SSLContext.getDefault();
        mWebSocketClient.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(sslContext));
        mWebSocketClient.connect();
    }catch (Exception e)
    {
    }

在库中,在WebSocketClient.java类中出现错误:

private final void interruptableRun() {
    if( channel == null ) {
        return;// channel will be initialized in the constructor and only be null if no socket channel could be created or if blocking mode could be established
    }

    try {
        String host;
        int port ;

        if( proxyAddress != null ) {
            host = proxyAddress.getHostName();
            port = proxyAddress.getPort();
        } else {
            host = uri.getHost();
            port = getPort();
        }
        channel.connect( new InetSocketAddress( host, port ) );
        conn.channel = wrappedchannel = createProxyChannel( wsfactory.wrapChannel( channel, null, host, port ) );

        timeout = 0; // since connect is over
        sendHandshake();
        readthread = new Thread( new WebsocketWriteThread() );
        readthread.start();
    } catch ( ClosedByInterruptException e ) {
        onWebsocketError( null, e );
        return;
    } catch ( /*IOException | SecurityException | UnresolvedAddressException*/Exception e ) {//
        onWebsocketError( conn, e );
        conn.closeConnection( CloseFrame.NEVER_CONNECTED, e.getMessage() );
        return;
    }

    ByteBuffer buff = ByteBuffer.allocate( WebSocketImpl.RCVBUF );
    try/*IO*/{
        while ( channel.isOpen() ) {
            if( SocketChannelIOHelper.read( buff, this.conn, wrappedchannel ) ) {
                conn.decode( buff );
            } else {
                conn.eot();
            }

            if( wrappedchannel instanceof WrappedByteChannel ) {
                WrappedByteChannel w = (WrappedByteChannel) wrappedchannel;
                if( w.isNeedRead() ) {
                    while ( SocketChannelIOHelper.readMore( buff, conn, w ) ) {
                        conn.decode( buff );
                    }
                    conn.decode( buff );
                }
            }
        }

    } catch ( CancelledKeyException e ) {
        conn.eot();
    } catch ( IOException e ) {
        conn.eot();
    } catch ( RuntimeException e ) {
        // this catch case covers internal errors only and indicates a bug in this websocket implementation
        onError( e );
        conn.closeConnection( CloseFrame.ABNORMAL_CLOSE, e.getMessage() );
    }
}

在这条线上:

channel.connect( new InetSocketAddress( host, port ) );

此外,如果您知道任何其他适用于所有设备的WebSocket库,我可以使用wss链接并放置自定义标头,请分享。

1 个答案:

答案 0 :(得分:0)

最后我找到了一个解决方案..这里是:

1)从libraty重写WebSocketClient.java类(或者只是提取库并将其粘贴到项目中)

2)创建新类:

import java.net.InetAddress;
import java.net.InetSocketAddress;

public class MyInetSocketAddress {

    public static InetSocketAddress myInetSocketAddress(String hostname, int port, boolean needResolved) 
    {
        if (hostname == null || port < 0 || port > 65535) {
            throw new IllegalArgumentException("host=" + hostname + ", port=" + port);
        }
        InetAddress addr = null;
        if (needResolved) {
            try {
                addr = InetAddress.getByName(hostname);
            } 
            catch (Exception ignored) 
            {
            }
        }
        return new InetSocketAddress(addr, port);
    }

}

3)打开你的WebSocketClient.java类,找到:

  

interruptableRun()

方法并替换它:

  

channel.connect(new InetSocketAddress(host,port));

这一个:

  

channel.connect(MyInetSocketAddress.myInetSocketAddress(host,port,true));

4)在方法结束时添加try / catch - 替换:

  

conn.closeConnection(CloseFrame.ABNORMAL_CLOSE,e.getMessage());

使用:

try{
    conn.closeConnection( CloseFrame.ABNORMAL_CLOSE, e.getMessage() );
}
catch (Exception e1)
{
}

5)此处另外添加catch(例外e):

private class WebsocketWriteThread implements Runnable {
    @Override
    public void run() {
        Thread.currentThread().setName( "WebsocketWriteThread" );
        try {
            while ( !Thread.interrupted() ) {
                SocketChannelIOHelper.writeBlocking( conn, wrappedchannel );
            }
        } catch ( IOException e ) {
            conn.eot();
        } catch ( InterruptedException e ) {
            // this thread is regularly terminated via an interrupt
        }
    }
}

如下所示:

private class WebsocketWriteThread implements Runnable {
    @Override
    public void run() {
        Thread.currentThread().setName( "WebsocketWriteThread" );
        try {
            while ( !Thread.interrupted() ) {
                SocketChannelIOHelper.writeBlocking( conn, wrappedchannel );
            }
        } catch ( IOException e ) {
            conn.eot();
        } catch ( InterruptedException e ) {
            // this thread is regularly terminated via an interrupt
        } catch (Exception e)
        {
        }

    }
}

6)另外,不要忘记使用它:

ProviderInstaller.installIfNeeded(getApplicationContext());
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
mWebSocketClient.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(sslContext));
mWebSocketClient.connect();

如上所述。

希望这会有所帮助!))如果您有任何问题 - 请问我)