资讯

展开

计算机网络-HTTP代理服务器

作者:快盘下载 人气:

啥也不说;上代码
把项目目录组织成这个样子
计算机网络-HTTP代理服务器

package main;

import constants.ProxyConstants;
import thread.ProxyThread;
import util.SerializationUtil;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Scanner;

/**
 * ProxySever
 *
 * ;author: lsxuan
 * ;email: 1146887979;QQ.com
 * ;create: 2022-10-03 20:13
 */
public class ProxySever {
    public static String cachePath;
    private static List<CacheUnit> cache;

    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket;
        Socket currsoket = null;
        /** users need to set up work space */

        System.out.println(;==============请输入缓存的存储目录;输入 d 则设置为默认目录;程序同一目录下;=================;);
        Scanner scanner = new Scanner(System.in);
        cachePath = scanner.nextLine();
        if (cachePath.equals(;d;)) {
            cachePath = ProxyConstants.DEFAULT_CACHE_PATH;
        }
        /** 初始化缓存写对象 */
        //readCache(cachePath);
        File cacheFile = new File(cachePath);
        //cacheFile.delete();
        if (!cacheFile.exists()) {
            cacheFile.createNewFile();
        }
        cache = ((SerializationUtil.readObjectForList(cacheFile)));
        System.out.println(;=================================== 工作目录设置完毕====================================;);

        try {
            //设置serversocket;绑定端口8888
            serverSocket = new ServerSocket(ProxyConstants.PROXY_PORT);
            int i = 0;

            //循环;持续监听从这个端口的所有请求
            while (true) {
                currsoket = serverSocket.accept();
                //启动一个新的线程来处理这个请求
                i;;;
                System.out.println(;启动第; ; i ; ;个线程;);
                new ProxyThread(currsoket).run();
            }
        } catch (IOException e) {

            e.printStackTrace();
        } finally {
            if (currsoket != null) {
                currsoket.close();//及时关闭这个socket
            }
            writeCache();
        }


    }

    synchronized public static void addCacheUnit(CacheUnit cacheUnit) {
        cache.add(cacheUnit);
    }

    synchronized public static boolean ifCacheEmpty() {
        return cache.isEmpty();
    }

    synchronized public static boolean ifCached(String requestLine) {
        if (requestLine == null) return false;
        for (CacheUnit unit : cache
        ) {
            if (unit.getRequestLine().equals(requestLine)) return true;
        }
        return false;
    }

    synchronized public static CacheUnit getCacheUnit(Integer index) {
        return cache.get(index).copy();
    }

    synchronized public static void removeCacheUnit(int cacheUrlIndex) {
        cache.remove(cacheUrlIndex);
    }
    synchronized public static void writeCache(){
        SerializationUtil.writeObject(cache, new File(cachePath));
    }
    synchronized public static String getModifyTime(String requestLine, Boolean ifHasTime, Integer cacheUrlIndex) {

        if (requestLine == null) throw new IllegalArgumentException();
        String LastModifiTime = null;
        for (int i = 0; i < cache.size(); i;;) {
            CacheUnit unit = cache.get(i);
            if (requestLine.equals(unit.getRequestLine())) {
                cacheUrlIndex = i;
                for (String line : unit.getLines()
                ) {
                    if (line.contains(;http://;))
                        break;
                    if (line.contains(;Last-Modified:;)) {
                        LastModifiTime = cachePath.substring(line.indexOf(;Last-Modified:;));
                        ifHasTime=true;
                        return LastModifiTime;
                    }
                    if (line.contains(;<html>;)) {
                        ifHasTime = false;
                        return LastModifiTime;
                    }
                }
            }
        }
        ifHasTime = false;
        return LastModifiTime;
    }
}

ProxyThread.java

package thread;

import constants.ProxyConstants;
import util.CacheUnit;
import main.ProxySever;
import util.Filter;

import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.StringTokenizer;

/**
 * ProxyThread
 *
 * ;author: lsxuan
 * ;email: 1146887979;qq.com
 * ;create: 2022-10-03 20:16
 */
public class ProxyThread implements Runnable {
    private Socket socket;

    public ProxyThread(Socket socket) {
        this.socket = socket;
        try {
            this.socket.setSoTimeout(ProxyConstants.TIMEOUT);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    ;Override
    public void run() {
        String ip = socket.getLocalAddress().getHostAddress();
        String requestLine = null;
        BufferedReader clientBufferedReader=null;
        try {
//            if(Filter.ipList.contains(ip)){
//                System.out.println(;---------用户已被屏蔽;);return;
//            }
            clientBufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(;从浏览器读取第一行....;);
            requestLine = clientBufferedReader.readLine();
            if(requestLine==null){
                System.out.println(;错误请求;);
                return;
            }

            if (!Filter.filter(requestLine)) {
                System.out.println(;请求; ; requestLine ; ;已被过滤;);
                return;
            }
        } catch (IOException e) {
            e.printStackTrace();
            try {
                if(clientBufferedReader!=null)clientBufferedReader.close();
                if(socket!=null)socket.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        System.out.println(requestLine);
        String[] hostAndPort = getHostAndPort(requestLine);
        String targetHost = hostAndPort[0];
        String targetPort = hostAndPort[1];
        System.out.println(;提取的主机名:; ; targetHost ; ; 提取的端口号: ; ; targetPort);
        String replacement = Filter.map(targetHost);
        String oldHost = targetHost;
        if (replacement != null) {
            requestLine=requestLine.replace(targetHost,replacement);

            targetHost = replacement;
            System.out.println(;请求已被重定向;);
        }

        //尝试连接目标主机
        Socket accessSocket = null;
        int retry = ProxyConstants.RETRIEVE;
        try {
            while (retry-- != 0 && (targetHost != null)) {
                accessSocket = new Socket(targetHost, Integer.parseInt(targetPort));
                if (accessSocket != null) break;
            }
            Thread.sleep(ProxyConstants.CONNECT_PAUSE);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        InputStream webInputStream = null;
        BufferedReader webBufferedReader = null;
        PrintWriter webPrintWriter = null;
        InputStream clientInputStream = null;
        OutputStream clientOutputStream = null;
        PrintWriter clientOutPrintWriter = null;
        if (accessSocket == null) {
            System.out.println(;目的主机;; ; targetHost ; ;:; ; targetPort ; ;连接失败;);
        } else {
            System.out.println(;目的主机;; ; targetHost ; ;连接成功;);
            System.out.println(;请求将发送至:; ; targetHost ; ;:; ; targetPort);
            try {
                accessSocket.setSoTimeout(ProxyConstants.TIMEOUT);

                webInputStream = accessSocket.getInputStream();//获取网站返回的响应
                webBufferedReader = new BufferedReader(new InputStreamReader(webInputStream));
                webPrintWriter = new PrintWriter(accessSocket.getOutputStream());
                clientInputStream = socket.getInputStream();//创建从浏览器获取请求的输入流
                clientOutputStream = socket.getOutputStream();//创建向浏览器发送响应的流
                clientOutPrintWriter = new PrintWriter(clientOutputStream);

                boolean ifCached = ProxySever.ifCached(requestLine);
                CacheUnit cacheUnit = new CacheUnit(requestLine);
                if (!ifCached) {
                    //将请求直接发往网站;并获取响应;记录响应至缓存
                    sendRequestToWeb(replacement,oldHost,requestLine, webPrintWriter, clientBufferedReader);
                    sendResponseToClient(false, -1, webInputStream, clientOutputStream, clientOutPrintWriter, cacheUnit);
                } else {//寻找之前缓存过该请求
                    Boolean ifHasTime = false;
                    Integer cacheUrlIndex = -1;
                    String modifyTime = ProxySever.getModifyTime(requestLine, ifHasTime, cacheUrlIndex);
                    System.out.println(;提取到的modifytime;; ; modifyTime);
                    String info = null;
                    //如果缓存的内容里面该请求是没有Last-Modify属性的;就不用向服务器查询If-Modify了;否则向服务器查询If-Modify
                    if (ifHasTime) {
                        StringBuilder msg = new StringBuilder();
                        msg.append(requestLine).append(;
;);
                        System.out.print(;向服务器发送确认修改时间请求:
; ; msg);
                        msg.append(;Host: ;).append(targetHost).append(;
;);
                        msg.append(;If-modified-since: ;).append(modifyTime).append(;

;);
                        webPrintWriter.write(msg.toString());
                        webPrintWriter.flush();
                        info = webBufferedReader.readLine();
                        System.out.println(;服务器发回的信息是;; ; info);
                    }
                    if (!ifHasTime||info.contains(ProxyConstants.NOT_MODIFIED) ) {//如果服务器给回的响应是304 Not Modified;就将缓存的数据直接发送给浏览器
                        System.out.println(;使用缓存数据;);
                        StringBuilder sb = new StringBuilder();
                        //
                        if (cacheUrlIndex != -1) {
                            sb.append(ProxySever.getCacheUnit(cacheUrlIndex).getContent()).append(;

;);
                            clientOutputStream.write(sb.toString().getBytes(), 0, sb.toString().length());
                            clientOutputStream.flush();
                        }

                    } else {
                        //服务器返回的不是304 Not Modified的话;就将服务器的响应直接转发到浏览器并记录缓存就好了
                        System.out.println(;有更新;使用新的数据;);
                        clientOutputStream.write(info.getBytes());
                        sendResponseToClient(true, cacheUrlIndex, webInputStream, clientOutputStream, clientOutPrintWriter, cacheUnit);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (webBufferedReader != null) webBufferedReader.close();
                    if (webPrintWriter != null) webPrintWriter.close();
                    if (clientBufferedReader != null) clientBufferedReader.close();
                    if (clientOutPrintWriter != null) clientOutPrintWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
        try {
            if (socket != null) socket.close();
            if (accessSocket != null) accessSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendRequestToWeb(String replacement,String oldHost,String requestLine, PrintWriter webPrintWriter, BufferedReader clientBufferedReader) throws IOException {
        String buffer = requestLine;

        System.out.print(;发送请求:
;);
        try {
            while (!buffer.equals(;;)) {
                buffer ;= ;
;;
                if (replacement!=null&&buffer.contains(;Host: ;)) {
                    buffer=buffer.replace(oldHost,replacement);
                }
                webPrintWriter.write(buffer);
                System.out.println(buffer);
                buffer = clientBufferedReader.readLine();
            }

        }catch (SocketTimeoutException ignored){

        }

        webPrintWriter.write(;
;);
        webPrintWriter.flush();
    }

    public void sendResponseToClient(boolean ifUpdate, Integer cacheUrlIndex, InputStream webInputStream, OutputStream clientOutputStream, PrintWriter clientOutPrintWriter, CacheUnit cacheUnit) {
        byte[] bytes = new byte[2048];
        int length = 0;
        try {
            while (true) {
                if ((length = webInputStream.read(bytes)) > 0) {
                    clientOutputStream.write(bytes, 0, length);
                    String show_response = new String(bytes, 0, bytes.length);
                    System.out.println(;服务器发回的消息是:
---
; ; show_response ; ;
---;);
                    //write cache
                    cacheUnit.getContent().append(bytes).append(;
;);
                    //if(webInputStream.available()<bytes.length)break;
                } else break;
            }

            clientOutPrintWriter.write(;
;);
            clientOutPrintWriter.flush();
        } catch (SocketTimeoutException ignored){

        }catch (IOException e) {
            e.printStackTrace();
        }
        if (ifUpdate) {
            ProxySever.removeCacheUnit(cacheUrlIndex);
        }
        ProxySever.addCacheUnit(cacheUnit);

    }

    public static String[] getHostAndPort(String requestLine) {

        String host;
        String port = null;
        String[] result = new String[2];
        int index;
        int portIndex;
        String temp;

        StringTokenizer stringTokenizer = new StringTokenizer(requestLine);
        stringTokenizer.nextToken();//丢弃第一个字串 这是请求类型 比如GET POST
        temp = stringTokenizer.nextToken();//这个字串里面有主机名和端口

        int index1 = temp.indexOf(;//;);
        host = temp.substring(index1 == -1 ? 0 : index1 ; 2);//比如 http://news.sina.com.cn/gov/2017-12-13/doc-ifypsqiz3904275.shtml -> news.sina.com.cn/gov/2017-12-13/doc-ifypsqiz3904275.shtml
        index = host.indexOf(;/;);
        if (index == -1) index = temp.length();
        if (index != -1) {
            host = host.substring(0, index);//比如 news.sina.com.cn/gov/2017-12-13/doc-ifypsqiz3904275.shtml -> news.sina.com.cn
            portIndex = host.indexOf(;:;);
            if (portIndex != -1) {
                port = host.substring(portIndex ; 1);//比如 www.ghostlwb.com:8080 -> 8080
                host = host.substring(0, portIndex);
            } else {//没有找到端口号;则加上默认端口号80
                port = ;80;;
            }
        }
        result[0] = host;
        result[1] = port;
        return result;
    }
    public static String getURL(String requestLine) {
        String[] questLine = requestLine.split(; ;);
        if (questLine.length != 3) throw new RuntimeException();
        return questLine[1];
    }
}

ProxyConstants.java

package constants;

/**
 * ProxyConstants
 *
 * ;author: lsxuan
 * ;email: 1146887979;qq.com
 * ;create: 2022-10-03 20:19
 */
public class ProxyConstants {
    public static final String DEFAULT_CACHE_PATH = ;default_cache.cah;;
    public static final int TIMEOUT = 10000;//response time out upper bound
    public static final int RETRIEVE = 5;//retry connection 5 times
    public static final int CONNECT_PAUSE = 5000;//waiting for connection
    public static final int PROXY_PORT = 8888;

    public static final String ILLEGAL_REQUEST = ;Illegal Request;;
    public static final String LAST_MODIFIED = ;Last-Modified;;
    public static final String NOT_MODIFIED = ;Not Modified;;
}

CacheUnit.java

package util;

import java.io.Serializable;

/**
 * CacheUnit
 *
 * ;author: lsxuan
 * ;email: 1146887979;qq.com
 * ;create: 2022-10-03 20:51
 */
public class CacheUnit implements Serializable {
    private static final long serialVersionUID = 2333333333333333L;
    private String requestLine;

    private StringBuilder content;

    public CacheUnit(String requestLine) {
        this.requestLine = requestLine;
        content = new StringBuilder();
    }

    public CacheUnit(String requestLine, StringBuilder content) {
        this.requestLine = requestLine;
        this.content = content;
    }

    public CacheUnit copy() {
        return new CacheUnit(this.requestLine, this.content);
    }


    public String getRequestLine() {
        return requestLine;
    }

    public void setRequestLine(String requestLine) {
        this.requestLine = requestLine;
    }

    public StringBuilder getContent() {
        return content;
    }

    public void setContent(StringBuilder content) {
        this.content = content;
    }

    public String getCacheContent() {
        StringBuilder sb = new StringBuilder();
        sb.append(requestLine).append(;
;);

        if (!(;;.equals(content) || content == null)) sb.append(content);
        return sb.toString();
    }

    public String[] getLines() {
        return content.toString().split(;
;);
    }
}

Filter.java

package util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Filter
 *
 * ;author: lsxuan
 * ;email: 1146887979;qq.com
 * ;create: 2022-10-03 21:46
 */
public class Filter {

    private static final Map<String, String> MAP;

    static {
        MAP = new HashMap<>();
        MAP.put(;http://www.tsinghua.edu.cn/;, ;http://www.hit.edu.cn/;);
        MAP.put(;today.hit.edu.cn;, ;jwts.hit.edu.cn;);
    }
private static final List<String> filterList;
    static {
        filterList = new ArrayList<>();
        filterList.add(;CONNECT;);
        filterList.add(;www.4399.com;);
    }
    /**
     * 过滤某些请求
     * ;param requestLine
     * ;return
     */
    public static boolean filter(String requestLine) {
        if (requestLine == null) return false;
        for (String str:filterList
             ) {
            if(requestLine.contains(str))return false;
        }
        return true;
    }

    /**
     * 获取钓鱼映射
     * ;param requestLine
     * ;return
     */
    public static String map(String requestLine) {
        return MAP.get(requestLine);
    }

    /**
     * 需要过滤的用户ip
     */
    public static final List<String> ipList;
    static {
        ipList = new ArrayList<>();
        ipList.add(;127.0.0.1;);
    }
}

SerializationUtil.java



;;;java
package util;

import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * SerializationUtil
 *
 * ;author: lsxuan
 * ;email: 1146887979;qq.com
 * ;create: 2022-10-04 19:21
 */
public class SerializationUtil {
    /**
     * 序列化,List
     */
    public static <T> boolean writeObject(List<T> list, File file) {
        T[] array = (T[]) list.toArray();
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(Files.newOutputStream(file.toPath()));
            out.writeObject(array);
            out.flush();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 反序列化,List
     */
    public static <E> List<E> readObjectForList(File file) {
        E[] object;
        ObjectInputStream in = null;
        try {
            in = new ObjectInputStream(Files.newInputStream(file.toPath()));
            object = (E[]) in.readObject();
            return new ArrayList<E>(Arrays.asList(object));
        } catch (EOFException e) {
            return new ArrayList<E>();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }
}



加载全部内容

相关教程
猜你喜欢
用户评论
快盘暂不提供评论功能!