java - 创建 java 代理客户端时出错
问题描述
我正在尝试在 java 中创建一个 Web 代理客户端。我偷了这些家伙的代码并对其进行了修改以创建一个服务器,现在是一个客户端,这样用户就可以下载并运行客户端来连接到服务器。我只想在终端上运行它,但我未来的计划是添加一个 gui。
这是服务器。这可以直接开箱即用,就像您在 Firefox 中输入 ip 一样,它会运行得很好。TLDR:它解析 URL 并将数据从客户端转发到服务器,反之亦然。
请求处理程序.java
/*
-----------------------------------------------------------------------------------------------
STOLEN FROM THIS MAN ON GITHUB
https://github.com/stefano-lupo/Java-Proxy-Server/blob/master/src/RequestHandler.java
-----------------------------------------------------------------------------------------------
*/
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;
public class RequestHandler implements Runnable {
/**
* Socket connected to client passed by Proxy server
*/
Socket clientSocket;
/**
* Read data client sends to proxy
*/
BufferedReader proxyToClientBr;
/**
* Send data from proxy to client
*/
BufferedWriter proxyToClientBw;
/**
* Thread that is used to transmit data read from client to server when using HTTPS
* Reference to this is required so it can be closed once completed.
*/
private Thread httpsClientToServer;
/**
* Creates a RequestHandler object capable of servicing HTTP(S) GET requests
* @param clientSocket socket connected to the client
*/
public RequestHandler(Socket clientSocket){
this.clientSocket = clientSocket;
try
{
this.clientSocket.setSoTimeout(2000);
proxyToClientBr = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
proxyToClientBw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
}
catch (IOException e)
{
System.out.println("Error on IO Exception");
e.printStackTrace();
}
}
/**
* Reads and examines the requestString and calls the appropriate method based
* on the request type.
*/
@Override
public void run() {
// Get Request from client
String requestString;
try{
requestString = proxyToClientBr.readLine();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error reading request from client");
return;
}
// Parse out URL
System.out.println("Request Received " + requestString);
// Get the Request type
String request = requestString.substring(0,requestString.indexOf(' '));
// remove request type and space
String urlString = requestString.substring(requestString.indexOf(' ')+1);
// Remove everything past next space
urlString = urlString.substring(0, urlString.indexOf(' '));
// Prepend http:// if necessary to create correct URL
if(!urlString.substring(0,4).equals("http")){
String temp = "http://";
urlString = temp + urlString;
}
// Check request type
if(request.equals("CONNECT")){
System.out.println("HTTPS Request for : " + urlString + "\n");
handleHTTPSRequest(urlString);
}
else
{
System.out.println("HTTP GET for : " + urlString + "\n");
sendNonCachedToClient(urlString);
}
}
/**
* Sends the contents of the file specified by the urlString to the client
* @param urlString URL ofthe file requested
*/
private void sendNonCachedToClient(String urlString){
try{
// Compute a logical file name as per schema
// This allows the files on stored on disk to resemble that of the URL it was taken from
int fileExtensionIndex = urlString.lastIndexOf(".");
String fileExtension;
// Get the type of file
fileExtension = urlString.substring(fileExtensionIndex, urlString.length());
// Get the initial file name
String fileName = urlString.substring(0,fileExtensionIndex);
// Trim off http://www. as no need for it in file name
fileName = fileName.substring(fileName.indexOf('.')+1);
// Remove any illegal characters from file name
fileName = fileName.replace("/", "__");
fileName = fileName.replace('.','_');
// Trailing / result in index.html of that directory being fetched
if(fileExtension.contains("/")){
fileExtension = fileExtension.replace("/", "__");
fileExtension = fileExtension.replace('.','_');
fileExtension += ".html";
}
fileName = fileName + fileExtension;
// Attempt to create File to cache to
boolean caching = true;
File fileToCache = null;
BufferedWriter fileToCacheBW = null;
try{
// Create File to cache
fileToCache = new File("cached/" + fileName);
if(!fileToCache.exists()){
fileToCache.createNewFile();
}
// Create Buffered output stream to write to cached copy of file
fileToCacheBW = new BufferedWriter(new FileWriter(fileToCache));
}
catch (IOException e){
System.out.println("Couldn't cache: " + fileName);
caching = false;
e.printStackTrace();
} catch (NullPointerException e) {
System.out.println("NPE opening file");
}
// Check if file is an image
if((fileExtension.contains(".png")) || fileExtension.contains(".jpg") ||
fileExtension.contains(".jpeg") || fileExtension.contains(".gif")){
// Create the URL
URL remoteURL = new URL(urlString);
BufferedImage image = ImageIO.read(remoteURL);
if(image != null) {
// Cache the image to disk
ImageIO.write(image, fileExtension.substring(1), fileToCache);
// Send response code to client
String line = "HTTP/1.0 200 OK\n" +
"Proxy-agent: ProxyServer/1.0\n" +
"\r\n";
proxyToClientBw.write(line);
proxyToClientBw.flush();
// Send them the image data
ImageIO.write(image, fileExtension.substring(1), clientSocket.getOutputStream());
// No image received from remote server
} else {
System.out.println("Sending 404 to client as image wasn't received from server"
+ fileName);
String error = "HTTP/1.0 404 NOT FOUND\n" +
"Proxy-agent: ProxyServer/1.0\n" +
"\r\n";
proxyToClientBw.write(error);
proxyToClientBw.flush();
return;
}
}
// File is a text file
else {
// Create the URL
URL remoteURL = new URL(urlString);
// Create a connection to remote server
HttpURLConnection proxyToServerCon = (HttpURLConnection)remoteURL.openConnection();
proxyToServerCon.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
proxyToServerCon.setRequestProperty("Content-Language", "en-US");
proxyToServerCon.setUseCaches(false);
proxyToServerCon.setDoOutput(true);
// Create Buffered Reader from remote Server
BufferedReader proxyToServerBR = new BufferedReader(new InputStreamReader(proxyToServerCon.getInputStream()));
// Send success code to client
String line = "HTTP/1.0 200 OK\n" +
"Proxy-agent: ProxyServer/1.0\n" +
"\r\n";
proxyToClientBw.write(line);
// Read from input stream between proxy and remote server
while((line = proxyToServerBR.readLine()) != null){
// Send on data to client
proxyToClientBw.write(line);
// Write to our cached copy of the file
if(caching){
fileToCacheBW.write(line);
}
}
// Ensure all data is sent by this point
proxyToClientBw.flush();
// Close Down Resources
if(proxyToServerBR != null){
proxyToServerBR.close();
}
}
// Close down resources
if(fileToCacheBW != null){
fileToCacheBW.close();
}
if(proxyToClientBw != null){
proxyToClientBw.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* Handles HTTPS requests between client and remote server
* @param urlString desired file to be transmitted over https
*/
private void handleHTTPSRequest(String urlString){
// Extract the URL and port of remote
String url = urlString.substring(7);
String pieces[] = url.split(":");
url = pieces[0];
int port = Integer.valueOf(pieces[1]);
try{
// Only first line of HTTPS request has been read at this point (CONNECT *)
// Read (and throw away) the rest of the initial data on the stream
for(int i=0;i<5;i++){
proxyToClientBr.readLine();
}
// Get actual IP associated with this URL through DNS
InetAddress address = InetAddress.getByName(url);
// Open a socket to the remote server
Socket proxyToServerSocket = new Socket(address, port);
proxyToServerSocket.setSoTimeout(5000);
// Send Connection established to the client
String line = "HTTP/1.0 200 Connection established\r\n" +
"Proxy-Agent: ProxyServer/1.0\r\n" +
"\r\n";
proxyToClientBw.write(line);
proxyToClientBw.flush();
// Client and Remote will both start sending data to proxy at this point
// Proxy needs to asynchronously read data from each party and send it to the other party
//Create a Buffered Writer betwen proxy and remote
BufferedWriter proxyToServerBW = new BufferedWriter(new OutputStreamWriter(proxyToServerSocket.getOutputStream()));
// Create Buffered Reader from proxy and remote
BufferedReader proxyToServerBR = new BufferedReader(new InputStreamReader(proxyToServerSocket.getInputStream()));
// Create a new thread to listen to client and transmit to server
ClientToServerHttpsTransmit clientToServerHttps =
new ClientToServerHttpsTransmit(clientSocket.getInputStream(), proxyToServerSocket.getOutputStream());
httpsClientToServer = new Thread(clientToServerHttps);
httpsClientToServer.start();
// Listen to remote server and relay to client
try {
byte[] buffer = new byte[4096];
int read;
do {
read = proxyToServerSocket.getInputStream().read(buffer);
if (read > 0) {
clientSocket.getOutputStream().write(buffer, 0, read);
if (proxyToServerSocket.getInputStream().available() < 1) {
clientSocket.getOutputStream().flush();
}
}
} while (read >= 0);
}
catch (SocketTimeoutException e) {
}
catch (IOException e) {
e.printStackTrace();
}
// Close Down Resources
if(proxyToServerSocket != null){
proxyToServerSocket.close();
}
if(proxyToServerBR != null){
proxyToServerBR.close();
}
if(proxyToServerBW != null){
proxyToServerBW.close();
}
if(proxyToClientBw != null){
proxyToClientBw.close();
}
} catch (SocketTimeoutException e) {
String line = "HTTP/1.0 504 Timeout Occured after 10s\n" +
"User-Agent: ProxyServer/1.0\n" +
"\r\n";
try{
proxyToClientBw.write(line);
proxyToClientBw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
catch (Exception e){
System.out.println("Error on HTTPS : " + urlString );
e.printStackTrace();
}
}
/**
* Listen to data from client and transmits it to server.
* This is done on a separate thread as must be done
* asynchronously to reading data from server and transmitting
* that data to the client.
*/
class ClientToServerHttpsTransmit implements Runnable{
InputStream proxyToClientIS;
OutputStream proxyToServerOS;
/**
* Creates Object to Listen to Client and Transmit that data to the server
* @param proxyToClientIS Stream that proxy uses to receive data from client
* @param proxyToServerOS Stream that proxy uses to transmit data to remote server
*/
public ClientToServerHttpsTransmit(InputStream proxyToClientIS, OutputStream proxyToServerOS) {
this.proxyToClientIS = proxyToClientIS;
this.proxyToServerOS = proxyToServerOS;
}
@Override
public void run(){
try {
// Read byte by byte from client and send directly to server
byte[] buffer = new byte[4096];
int read;
do {
read = proxyToClientIS.read(buffer);
if (read > 0) {
proxyToServerOS.write(buffer, 0, read);
if (proxyToClientIS.available() < 1) {
proxyToServerOS.flush();
}
}
} while (read >= 0);
}
catch (SocketTimeoutException ste)
{
ste.printStackTrace();
}
catch (IOException e) {
System.out.println("Proxy to client HTTPS read timed out");
e.printStackTrace();
}
}
}
}
这是客户端。它似乎不起作用,我真的不明白为什么,因为它只是服务器的修改版本。
请求处理程序.java
/*
-----------------------------------------------------------------------------------------------
STOLEN FROM THIS MAN ON GITHUB
https://github.com/stefano-lupo/Java-Proxy-Server/blob/master/src/RequestHandler.java
-----------------------------------------------------------------------------------------------
*/
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;
public class RequestHandler implements Runnable
{
/**
* Socket connected to client passed by Proxy server
*/
Socket clientSocket;
/**
* Read data client sends to proxy
*/
BufferedReader clientToClientBr;
/**
* Send data from proxy to client
*/
BufferedWriter clientToClientBw;
/**
* Thread that is used to transmit data read from client to server when using HTTPS
* Reference to this is required so it can be closed once completed.
*/
private Thread threads;
/**
* Creates a RequestHandler object capable of servicing HTTP(S) GET requests
* @param clientSocket socket connected to the client
*/
public RequestHandler(Socket clientSocket)
{
this.clientSocket = clientSocket;
try
{
this.clientSocket.setSoTimeout(2000);
clientToClientBr = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
clientToClientBw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
}
catch (IOException e)
{
System.out.println("Error on IO Exception");
e.printStackTrace();
}
}
/**
* Reads and examines the requestString and calls the appropriate method based
* on the request type.
*/
@Override
public void run()
{
// Get Request from client
String requestString;
try
{
requestString = clientToClientBr.readLine();
System.out.println(requestString);
sendToServer(requestString);
}
catch (IOException e)
{
e.printStackTrace();
System.out.println("Error reading request from client");
return;
}
}
private void sendToServer(String urlString) throws IOException
{
// Open a socket to the remote server
Socket proxyToServerSocket = new Socket("192.168.0.226", 8080);
proxyToServerSocket.setSoTimeout(5000);
// Client and Remote will both start sending data to proxy at this point
// Proxy needs to asynchronously read data from each party and send it to the other party
//Create a Buffered Writer betwen proxy and remote
BufferedWriter proxyToServerBW = new BufferedWriter(new OutputStreamWriter(proxyToServerSocket.getOutputStream()));
// Create Buffered Reader from proxy and remote
BufferedReader proxyToServerBR = new BufferedReader(new InputStreamReader(proxyToServerSocket.getInputStream()));
// Create a new thread to listen to client and transmit to server
ClientToServerHttpsTransmit clientToServerHttps = new ClientToServerHttpsTransmit(clientSocket.getInputStream(), proxyToServerSocket.getOutputStream());
threads = new Thread(clientToServerHttps);
threads.start();
// Listen to remote server and relay to client
try {
byte[] buffer = new byte[4096];
int read;
do
{
read = proxyToServerSocket.getInputStream().read(buffer);
if (read > 0)
{
clientSocket.getOutputStream().write(buffer, 0, read);
if (proxyToServerSocket.getInputStream().available() < 1)
{
clientSocket.getOutputStream().flush();
}
}
} while (read >= 0);
}
catch (SocketTimeoutException e) {
}
catch (IOException e) {
e.printStackTrace();
}
// Close Down Resources
if(proxyToServerSocket != null){
proxyToServerSocket.close();
}
if(proxyToServerBR != null){
proxyToServerBR.close();
}
if(proxyToServerBW != null){
proxyToServerBW.close();
}
if(clientToClientBw != null){
clientToClientBw.close();
}
}
}
/**
* Listen to data from client and transmits it to server.
* This is done on a separate thread as must be done
* asynchronously to reading data from server and transmitting
* that data to the client.
*/
class ClientToServerHttpsTransmit implements Runnable
{
InputStream proxyToClientIS;
OutputStream proxyToServerOS;
/**
* Creates Object to Listen to Client and Transmit that data to the server
* @param proxyToClientIS Stream that proxy uses to receive data from client
* @param proxyToServerOS Stream that proxy uses to transmit data to remote server
*/
public ClientToServerHttpsTransmit(InputStream proxyToClientIS, OutputStream proxyToServerOS)
{
this.proxyToClientIS = proxyToClientIS;
this.proxyToServerOS = proxyToServerOS;
}
@Override
public void run()
{
try
{
// Read byte by byte from client and send directly to server
byte[] buffer = new byte[4096];
int read;
do
{
read = proxyToClientIS.read(buffer);
if (read > 0)
{
proxyToServerOS.write(buffer, 0, read);
if (proxyToClientIS.available() < 1)
{
proxyToServerOS.flush();
}
}
} while (read >= 0);
}
catch (SocketTimeoutException ste)
{
ste.printStackTrace();
}
catch (IOException e)
{
System.out.println("Proxy to client HTTPS read timed out");
e.printStackTrace();
}
}
}
我认为错误出现在客户端的请求处理程序中,因为我在客户端收到的错误消息是:
Wating for client to connect on port 8080
Got CONNECT www.youtube.com:443 HTTP/1.1
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at ClientToServerHttpsTransmit.run(RequestHandler.java:186)
at java.lang.Thread.run(Thread.java:748)
这是服务器上终端的错误:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at RequestHandler.run(RequestHandler.java:75)
at java.lang.Thread.run(Thread.java:748)
Error reading request from client
解决方案
推荐阅读
- python - Python将字典拆分为字典列表
- arrays - 如何在python中多个矩阵和数字范围
- python - 3D 图形。添加 Z 分量
- python - 如何在 Django Rest Framework 中禁用节流以进行测试?
- python - pip3 "build" 不会安装(已解决)
- python - 为什么我的 Cloud Run 出现 Broken Pipe 错误?
- javascript - 检测用户是否尝试调整可拖动元素的大小
- javascript - 如何访问从云函数(kotlin/typescript)返回给客户端的数组元素?
- c# - 捕获缺少页面扩展的 URL
- r - 映射时函数返回所有值而不是一个