我正在使用Java构建代理服务器;服务器正确处理HTTP流量但无法正确隧道传输HTTPS流量。根据{{3}},进行以下过程:
1)我成功从包含要以纯文本连接的HOST的浏览器收到CONNECT消息。
2)我解析此消息以提取主机详细信息并成功建立与远程主机的连接。
3)然后我将HTTP / 1.0 200连接已建立的消息发送回客户端,然后立即尝试使用以下代码从连接的任一侧中继流量。
问题是在我返回上述200条消息而不是发送HTTPS数据后,浏览器似乎进入无限循环并继续向代理发送更多CONNECT消息。这是我用来在客户端和主机之间中继数据的代码:
public static void stageTunnelledConnection(Socket clientSocket,Socket targetHostSocket) throws IOException{
//set client socket read timeout to 2 seconds. The targethost connection will ALREADY have been
//set to this value at the time this method is called.
clientSocket.setSoTimeout(2000);
InputStream[] socketInputStreamsArr = new InputStream[]{clientSocket.getInputStream(),targetHostSocket.getInputStream()};
OutputStream[] socketOutputStreamsArr = new OutputStream[]{clientSocket.getOutputStream(),targetHostSocket.getOutputStream()};
//holds current socket index to read from, this will be switched between the two sockets
//at 0 and 1 indexes of the sockets array respectively.
int curReadIndex = 0;
//this will be set according to the "curReadIndex" value and will typically be
//the logical NOT of that value; that is, where curReadIndex equals 0 the curWriteIndex to will equal 1 and visa versa.
int curWriteIndex = 1;
while(true){
try{
//attempt to read from socket stream at current index and write
//to the socket at the alternate index.
byte[] dataBuff = new byte[2048];
int bytesRead = 0;
//we read into the dataBuff this operation will block for
//a max of 2 seconds should no data be available to read
while((bytesRead = socketInputStreamsArr[curReadIndex].read(dataBuff)) != -1){
//ByteArrayInputStream bais = new ByteArrayInputStream(dataBuff);
//BufferedReader br = new BufferedReader(new InputStreamReader(bais));
//System.out.println(br.readLine());
//write the buffer to the outputsteam at the index
//computed and stored to the "curWriteIndex" var above.
socketOutputStreamsArr[curWriteIndex].write(dataBuff);
socketOutputStreamsArr[curWriteIndex].flush();
//System.out.println("Bytes read=".concat(String.valueOf(dataBuff)));
//System.out.println("wroteBytes: "+bytesRead);
}
}
catch(SocketTimeoutException ste){
//we switch read/write index each time a read timeout error occurs. I.e
//were there is no further data to read from the socket at the currrent read index.
if(ste.getMessage().contains("Read")){
//System.out.println("Switching connection.");
curReadIndex = (curReadIndex == 0) ? 1 : 0;
curWriteIndex = (curReadIndex == 0) ? 1 : 0;
}
else{
//clientSocket.close();
//targetHostSocket.close();
ste.printStackTrace();
}
}
catch(SocketException ioe){
//if an input/output exception occurs we must close both sockets
clientSocket.close();
targetHostSocket.close();
ioe.printStackTrace();
}
}
}
**重要提示:** 由于被隧道化的实际数据是加密的,因此对代理是不透明的,因此代理必须准备好随时从任何一方读/写。为了在单个线程中促进这个过程,我在两侧设置了一个相对较短的Socket Timeout(2秒)并进入一个循环,该循环交替显示每次迭代读取和写入的哪一侧,其中没有数据可用SocketTimeoutException发生被捕获,此时要切换读取的一侧并且循环继续执行。这个旨在从单个线程中的两个套接字读取的策略是否会导致问题?
答案 0 :(得分:1)
socketOutputStreamsArr[curWriteIndex].write(dataBuff);
那应该是
socketOutputStreamsArr[curWriteIndex].write(dataBuff, 0, bytesRead);
为了在单个线程中促进此过程,我在两侧设置了一个相对较短的Socket Timeout(2秒)并进入一个循环,该循环交替显示每次迭代读取和写入的哪一侧,其中没有数据如果发生SocketTimeoutException,则会捕获,此时要切换读取的一侧并继续执行循环。这个旨在从单个线程中的两个套接字读取的策略是否会导致问题?
是。您应该使用两个线程或非阻塞NIO。否则你只是增加了许多不必要的延迟。