【发布时间】:2020-01-04 10:06:09
【问题描述】:
我想用套接字在 kotlin 中创建一个代理。我创建了一个套接字服务器,它将客户端(google.com)连接到一个套接字。来自google的http请求是:
CONNECT www.google.com:443 HTTP/1.1
Host: www.google.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
所以我发送到套接字:
HTTP/1.1 200 Connection Established
Connection: close
然后谷歌发送:
; 7����r���9 ����l&�����cO��9���� �.rW�Vs9�T���}�$_aX�ys��&�X "���+�/�,�0̨̩�� � � / 5
��� www.google.com �
zz # hhttp/1.1
3 + )zz
(��>�%܇� �fT5
��5��ue�u��` - +
** ZZ ) � � +c���>L����#9�����'���Ʌͩ�5��h�Bn��O�G)�� ����f�^���S�d|bC�7VT5�:���^�QSRך`MM�g#�[�|\�T�9h@�K:7?��t��49 �;`�ʛ�"��ٹ��9����H�f�@��=�����2���(��T)B�`�#�nhS���!뷊��E�ao����/z)e��}���,>�����G��B�� ! ��OF�p�-�>q
我使用新的 ssl 套接字将这些字节发送到域 google.com 和端口 443,但这不起作用。回应是:
HTTP/1.0 400 Bad Request
Content-Length: 54
Content-Type: text/html; charset=UTF-8
Date: Sat, 31 Aug 2019 14:16:46 GMT
<html><title>Error 400 (Bad Request)!!1</title></html>
我的代码:
fun createServerSocket() {
println("Starting Server")
val server_socket = ServerSocket(555)
Thread{
val connection_socket = server_socket.accept()
//connection_socket.soTimeout = 2000
_handleConnectionSocket(connection_socket)
}.start()
}
private fun _handleConnectionSocket(client_socket: Socket) {
Thread{
val client_inputStream = client_socket.getInputStream()
val client_outputStream = client_socket.getOutputStream()
val client_bufferedWriter = BufferedWriter(OutputStreamWriter(client_outputStream))
val ssf = SSLSocketFactory.getDefault() as SSLSocketFactory
val server_socket = ssf.createSocket("google.com", 443)
val server_inputStream = server_socket.getInputStream()
val server_outputStream = server_socket.getOutputStream()
var should_save = false
Thread{
try {
val buffer = ByteArray(4096)
do {
val read = client_inputStream.read(buffer)
if (should_save) {
if (read > 0) {
server_outputStream.write(buffer, 0, read)
if (client_inputStream.available() < 1)
server_outputStream.flush()
}
}
} while (read >= 0)
} catch (e: java.net.SocketTimeoutException) {}
}.start()
Thread.sleep(1000)
should_save = true
val client_success_response =
"""
HTTP/1.1 200 Connection Established
Connection: close
""".trimIndent()
client_bufferedWriter.appendln(client_success_response)
client_bufferedWriter.flush()
Thread.sleep(800)
try {
val buffer = ByteArray(4096)
do {
val read = server_inputStream.read(buffer)
if (read > 0) {
client_outputStream.write(buffer, 0, read)
if (server_inputStream.available() < 1)
client_outputStream.flush()
}
} while (read >= 0)
} catch (e: java.net.SocketTimeoutException) {}
println("Fertig")
}.start()
}
我做错了什么?
【问题讨论】:
-
我猜你描述的不是你实际做的。请显示实际代码。请注意,这些是二进制数据(TLS 握手和加密数据),因此它们在您的代码和问题中都应该被视为二进制(即,将这些作为文本包含在文本中是没有意义的,因为将数据编码为十六进制)。此外,您似乎混淆了客户端和服务器:CONNECT 是由客户端(浏览器)而不是谷歌发送的。类似的二进制输出来自客户端而不是谷歌。
-
好的,谢谢。如果这是握手,我如何从谷歌获得请求?
-
没有“来自谷歌的请求”。在 HTTP(和 HTTPS)中,客户端(浏览器)发送 request,服务器(google)在收到客户端的请求后发送 response。但是在 CONNECT 的情况下,您只需在客户端(浏览器)和服务器(谷歌)之间创建一条隧道,并将所有数据从客户端不变地转发到服务器和服务器到客户端。您处理的唯一 HTTP 请求是从客户端到代理的 CONNECT 请求,唯一的 HTTP 响应是代理发送给客户端的响应。从那时起,一切都由代理转发。
-
是的,对不起。我如何从浏览器获取请求,例如谷歌搜索?
-
我想您已经明白 CONNECT 的工作原理是完全错误的。客户端(浏览器)向代理发送一个 CONNECT 请求,其中包括它想要连接的主机名和端口。代理创建到请求的服务器的 TCP(不是 SSL)连接。如果成功建立此连接,则代理向浏览器发送
HTTP/1.1 200 Connection Established...响应。从那时起,代理将简单地在客户端和服务器之间双向转发所有数据。