啥也不说;上代码
把项目目录组织成这个样子
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; } }