Java中的代理输入/输出流问题

Java中的代理输入/输出流问题,java,proxy,inputstream,outputstream,Java,Proxy,Inputstream,Outputstream,我已经尝试了一些不同的方法来让我的定制代理工作,到目前为止,我唯一能够做到的方法就是使用Apache的HttpClient。但是,为了了解情况,我想知道为什么我自己的代理句柄实现会遇到以下问题: public void processProxyRequest (Socket client, String request) throws Exception { if ( !request.equals("") ) { String[] requestH

我已经尝试了一些不同的方法来让我的定制代理工作,到目前为止,我唯一能够做到的方法就是使用Apache的HttpClient。但是,为了了解情况,我想知道为什么我自己的代理句柄实现会遇到以下问题:


public void processProxyRequest (Socket client, String request) throws Exception {

        if ( !request.equals("") ) {

            String[] requestHeaders = request.split("\\r\\n");
            Pattern p = Pattern.compile("([A-Z]*)\\s*([^:\\/]*):\\/\\/([^\\s]*)\\s*(?:HTTP.*)");
            Matcher m = p.matcher(requestHeaders[0]);

            if ( m.matches() ) {
                String method = m.group(1).toUpperCase();
                String proto = m.group(2).toLowerCase();
                String[] requestInfo = m.group(3).split("\\/", 2);

                String host = requestInfo[0];
                host = ( host.split("\\.").length < 3 ) ? "www." + host : host;
                String page = "/";
                if ( requestInfo.length == 2 && !requestInfo[1].equals("") ) {
                    page += requestInfo[1];
                }

                int remotePort = 80;

                if ( proto.equals("https") ) {
                    remotePort = 443;
                }
                else if ( proto.equals("ftp") ) {
                    remotePort = 21;
                }
                this.sendAndReceive(client, request, host, remotePort);
            }
        }

    }

    public void sendAndReceive (Socket client, String request, String host, int port) throws Exception {
        Socket target = new Socket(host, port);
        System.out.println("Connected to server");

        ByteArrayInputStream inStream = new ByteArrayInputStream(request.getBytes());

        this.inToOut(inStream, target.getOutputStream());
        System.out.println("Sent");
        this.inToOut(target.getInputStream(), client.getOutputStream());
        System.out.println("Received");
        target.close();
    }

    public void inToOut (InputStream input, OutputStream output) throws IOException {
        byte[] buffer = new byte[1024]; // Adjust if you want
        int bytesRead;
        System.out.println("reading");
        while ((bytesRead = input.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
    }

public void processProxyRequest(套接字客户端、字符串请求)引发异常{
如果(!request.equals(“”){
字符串[]requestHeaders=request.split(\\r\\n”);
Pattern p=Pattern.compile(([A-Z]*)\\s*([^:\\/]*):\\/\\/([^\\s]*)\\s*(?:HTTP.]);
Matcher m=p.Matcher(requestHeaders[0]);
如果(m.matches()){
String方法=m.group(1.toUpperCase();
字符串proto=m.group(2.toLowerCase();
字符串[]requestInfo=m.group(3.split(“\\/”,2);
字符串host=requestInfo[0];
主机=(host.split(“\\”)。长度<3)?“www.”+主机:主机;
字符串页=“/”;
if(requestInfo.length==2&&!requestInfo[1]。等于(“”){
页面+=请求信息[1];
}
int remotePort=80;
if(协议等于(“https”)){
远程端口=443;
}
else if(协议等于(“ftp”)){
远程端口=21;
}
this.sendReceive(客户端、请求、主机、远程端口);
}
}
}
public void sendAndReceive(套接字客户端、字符串请求、字符串主机、int端口)引发异常{
套接字目标=新套接字(主机、端口);
System.out.println(“连接到服务器”);
ByteArrayInputStream inStream=newbytearrayinputstream(request.getBytes());
this.intout(inStream,target.getOutputStream());
系统输出打印项次(“发送”);
this.intout(target.getInputStream(),client.getOutputStream());
系统输出打印项次(“收到”);
target.close();
}
public void intout(InputStream输入,OutputStream输出)引发IOException{
byte[]buffer=新字节[1024];//如果需要,请调整
int字节读取;
系统输出打印项次(“读取”);
而((bytesRead=input.read(buffer))!=-1){
输出写入(缓冲区,0,字节读取);
}
}
简而言之(不考虑我的请求头解析缺陷),上面的代码是编译和运行的,但是,
intout()
方法在input.read()过程中似乎有点挣扎和锁定,我不太清楚为什么。我确实知道我传递的原始套接字是有效的,并且打开时没有错误。此外,intoot()函数中的
System.out
会打印“reading”,但不会超过
read()
部分


谢谢你的建议

这不是编写代理的方法。在HTTP的情况下,您只需要处理第一行,它告诉您目标主机。其他一切都只是来回复制字节,需要进行一些小改进,例如正确报告上游连接错误和正确处理关机。FTP的情况比较棘手,应该完全分开处理,但是一旦你通过了连接阶段,它只是在复制字节。理解协议越轻松,协议就越简单越好。

在sendAndReceive函数中,可以尝试使用DataInputStream和DataOutputStream

public void sendAndReceive (Socket client, String request, String host, int port) throws Exception {
    Socket target = new Socket(host, port);
    System.out.println("Connected to server");

    this.inToOut(new DataInputStream(client.getInputStream()), new DataOutputStream(target.getOutputStream()));
    System.out.println("Sent");
    this.inToOut(new DataInputStream(target.getInputStream()), new DataOutputStream(client.getOutputStream()));
    System.out.println("Received");
    target.close();
}

问题似乎不在inToOut函数中-我尝试过使用inToOut(),效果很好(它实际上帮助我解决了类似的问题-谢谢)

我理解,这就是为什么请求行实际上已经传递到processRequest()方法中的原因。我为以后的日志功能做了一些额外的解析,而我想跟踪某些请求和响应头属性。至于来回“简单”复制字节,上面的内容有什么不正确的地方?我相当确定这就是我所做的,将in-stream从客户机复制到目标的out-stream,然后从target-in-stream复制到client-in-stream。但是仍然没有成功。如果没有看到复制代码,就不可能进行评论。除非使用NIO,否则每个连接需要两个线程,每个方向一个线程进行复制。当然,这两种方法的代码是相同的,它们只是在EOS之前读取和写入字节。已经有了代码,即
intout()
方法,该方法尝试将字节从客户端的输入流复制到目标服务器的输出流。当然,我没有将它们放在单独的线程中,但刚才我尝试使用线程,后来又尝试使用NIO,但这两次尝试似乎都是将数据写入目标服务器(对于我的测试,只有google.com),但在尝试读取响应时,它们总是冻结。