我正在尝试使用Java (Android)来连接到一个带有SSL套接字的服务器。请注意,这不是HTTP数据。这是一种混合了文本和二进制数据的专有协议。
我想通过HTTP代理中继SSL连接,但是我遇到了很多问题。现在我使用的场景和我的浏览器似乎使用的场景与Squid代理如下:
[客户端]-> [HTTP连接]-> [代理]-> [SSL连接]-> [服务器]
这对于浏览器来说是有效的,因为代理在建立ssl连接后会立即进行TLS协商。然而,我的代码似乎没有这样做。
我遇到的问题是 createSocket 永远不会返回。在代理机器上使用 Wireshark 能够看到代理和服务器之间进行了 TCP 握手。使用 Web 会话转储时,我可以看到客户端通常在此时启动 SSL 握手,但在我的情况下没有发生。
这不是信任管理器的问题,因为证书从未返回给我,也从未得到验证。
编辑:
经过讨论,这是我尝试运行的更完整版本代码。上面的简单 (new Socket(...)) 参数是我后来尝试的内容。
我正在调试的原始代码版本会抛出以下异常: java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (连接超时)
序列如下(稍微简化一下):
然后使用以下代码读取响应:
我想通过HTTP代理中继SSL连接,但是我遇到了很多问题。现在我使用的场景和我的浏览器似乎使用的场景与Squid代理如下:
[客户端]-> [HTTP连接]-> [代理]-> [SSL连接]-> [服务器]
这对于浏览器来说是有效的,因为代理在建立ssl连接后会立即进行TLS协商。然而,我的代码似乎没有这样做。
final TrustManager[] trustManager = new TrustManager[] { new MyX509TrustManager() };
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManager, null);
SSLSocketFactory factory = context.getSocketFactory();
Socket s = factory.createSocket(new Socket(proxy_ip, 3128), hostName, port, true);
我遇到的问题是 createSocket 永远不会返回。在代理机器上使用 Wireshark 能够看到代理和服务器之间进行了 TCP 握手。使用 Web 会话转储时,我可以看到客户端通常在此时启动 SSL 握手,但在我的情况下没有发生。
这不是信任管理器的问题,因为证书从未返回给我,也从未得到验证。
编辑:
经过讨论,这是我尝试运行的更完整版本代码。上面的简单 (new Socket(...)) 参数是我后来尝试的内容。
我正在调试的原始代码版本会抛出以下异常: java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (连接超时)
序列如下(稍微简化一下):
final Socket proxySocket = new Socket();
proxySocket.connect(proxyAddress, 2000); // 2 seconds as the connection timeout for connecting to the proxy server
[Start a thread and write to outputStream=socket.getOutputStream()]
final String proxyRequest = String.format("CONNECT %s:%d HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s:%d\r\n\r\n", hostName, port, hostName, port);
outputStream.close(); // Closing or not doesn't change anything
[Stop using that thread and let it exit by reaching the end of its main function]
然后使用以下代码读取响应:
final InputStreamReader isr = new InputStreamReader(proxySocket.getInputStream());
final BufferedReader br = new BufferedReader(isr);
final String statusLine = br.readLine();
boolean proxyConnectSuccess = false;
// readLine consumed the CRLF
final Pattern statusLinePattern = Pattern.compile("^HTTP/\\d+\\.\\d+ (\\d\\d\\d) .*");
final Matcher statusLineMatcher = statusLinePattern.matcher(statusLine);
if (statusLineMatcher.matches())
{
final String statusCode = statusLineMatcher.group(1);
if (null != statusCode && 0 < statusCode.length() && '2' == statusCode.charAt(0))
{
proxyConnectSuccess = true;
}
}
// Consume rest of proxy response
String line;
while ( "".equals((line = br.readLine())) == false )
{
}
我可以说这段代码能够工作,因为它在没有SSL的情况下就能正常运行。这里创建的套接字proxySocket
会被传递给createSocket
函数,而不是像原始示例中一样即兴创建一个新的套接字。