尝试用Java编写一个非常简单的、基本的线程HTTP代理服务器,并且我已经取得了很好的进步:
-
客户端连接服务器,输入输出
-
从GET请求中提取目标URL
-
与目标web服务器建立连接,并建立输入流
现在我明白我需要发送来自服务器输入流的数据并转发它到客户端输出流,但如何准确地做到这一点我不明白。我经验的广度与输入和输出流一直发送单个字符串,我没有一个坚实的理解这些流是如何工作的
我应该从输入流中读取所有数据到文件中,然后写入输出流吗?有没有更优雅的解决方案?
下面是我的代码:import java.io.*;
import java.net.*;
import java.util.*;
public class Proxy {
/////////////////////////////////////
public static void go(){
int incomingport = 50000;
ServerSocket myproxysocket = null;
try{
myproxysocket = new ServerSocket(incomingport);
while(true){
System.out.println("HTTP Java Proxy Server");
System.out.println();
System.out.println("Listening on port 50000...Press CTRL+C to exit");
System.out.println();
Socket client = myproxysocket.accept();
Thread t = new Thread(new ClientHandler(client));
t.start();
}//end while
}//end try
catch(Exception E){
E.printStackTrace();
}
}//end method go()
///////////////////////////////////
public static void main(String args[]) {
Proxy myserver = new Proxy();
myserver.go();
}//end main
}//end class proxy
/////////////////////////////////////////////////////////////////////////////////////
class ClientHandler implements Runnable{
private final DataInputStream clientin;
private final DataOutputStream clientout;
private final Socket clientSocket;
//constructor----------------
public ClientHandler(Socket incomingSocket) throws IOException{
clientSocket = incomingSocket;
clientin = new DataInputStream(incomingSocket.getInputStream());
clientout = new DataOutputStream(incomingSocket.getOutputStream());
}//--------------------------
////////////////////
public void run(){
try{
//Get URL from client
String getrequestline = clientin.readLine();
String targetURL = null;
String clientIP = null;
StringTokenizer st = new StringTokenizer(getrequestline);
st.nextToken();
targetURL = st.nextToken();
clientIP = clientSocket.getRemoteSocketAddress().toString();
System.out.println();
System.out.println("IP: " + clientIP);
System.out.println("Requested URL: " + targetURL);
System.out.println();
//connect to target URL
URL url = new URL(targetURL);
URLConnection targetconnection = url.openConnection();
targetconnection.setDoInput(true);
targetconnection.setDoOutput(false);
InputStream is = targetconnection.getInputStream();
//How do I read in from is and write out to clientout?
//clientout.write(???????)
}//try
catch(Exception E){
E.printStackTrace();
}//catch
finally{
try{clientSocket.close();}
catch(Exception ee){}
}//finally
}//end run----------
}//end CLASS--------------------------------------------------------------------------
有一个非常简洁的Utility类
org.apache.commons.io.IOUtils
来自common -io包。如果可以的话,使用它。否则,一个简单的方法(不使用任何NIO的东西)是这样的:
public static void copy(InputStream is, OutputStream os) throws IOException {
byte[] buff = new byte[1024*1024];
int a = 0;
while((a = is.read(buff)) > -1) {
// a is the number of bytes ACTUALLY read, so
// when we write, that's the number of bytes to write
os.write(buff,0,a);
}
os.flush();
}
和往常一样,不要忘记冲洗。