我在使用WebSocket Secure时遇到了这个问题。我使用这个websocket库:'org.java-websocket:Java-WebSocket:1.3.0'。这个问题只出现在联想的智能手机上(不是所有型号的手机都有问题,比如联想A6000就能正常工作)。例如,在联想Vibe设备上发生错误。我在Nexus 4、Nexus 5、Nexus 5x、Nexus 6、Nexus 6P、联想A6000、联想Vibe、三星Galaxy SIII (CyanogenMod Android 4.4.4)上进行了测试。此列表中只有联想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() );
}
}
On This Line:
channel.connect( new InetSocketAddress( host, port ) );
另外,如果你知道任何其他WebSocket库可以在所有设备上正常工作,在那里我可以使用wss链接并放置自定义头,请分享。
最后我找到了一个解决办法。这里是:
1)从库中重写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 ()
方法并替换为:
频道。
连接InetSocketAddress(主机,端口);
和这个:
频道。连接(MyInetSocketAddress。myInetSocketAddress(host, port, true));
4)还在方法的末尾添加try/catch - replace:
。closeConnection (CloseFrame。
异常关闭,e.t getmessage ());
:
try{
conn.closeConnection( CloseFrame.ABNORMAL_CLOSE, e.getMessage() );
}
catch (Exception e1)
{
}
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)
{
}
}
}
另外,不要忘记使用这个:
ProviderInstaller.installIfNeeded(getApplicationContext());
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
mWebSocketClient.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(sslContext));
mWebSocketClient.connect();
如上所示。
希望这对其他人有帮助!))如果你有任何问题-问我