兼容https和http协议的java代理服务器代码

阅读: 评论:0

兼容https和http协议的java代理服务器代码

兼容https和http协议的java代理服务器代码

最近做的一个http代理小程序,同时支持http和http。

1、获取http代理请求的头部信息,区分https还是http,做不同的处理

/*** 解析头部信息**/
public final class HttpHeader {private List<String> header=new ArrayList<String>();private String method;private String host;private String port;public static final int MAXLINESIZE = 4096;public static final String METHOD_GET="GET";public static final String METHOD_POST="POST";public static final String METHOD_CONNECT="CONNECT";private HttpHeader(){}/*** 从数据流中读取请求头部信息,必须在放在流开启之后,任何数据读取之前* @param in* @return* @throws IOException*/public static final HttpHeader readHeader(InputStream in) throws IOException {HttpHeader header = new HttpHeader();StringBuilder sb = new StringBuilder();//先读出交互协议来,char c = 0;while ((c = (char) in.read()) != 'n') {sb.append(c);if (sb.length() == MAXLINESIZE) {//不接受过长的头部字段break;}}//如能识别出请求方式则则继续,不能则退出if(header.String())!=null){do {sb = new StringBuilder();while ((c = (char) in.read()) != 'n') {sb.append(c);if (sb.length() == MAXLINESIZE) {//不接受过长的头部字段break;}}if (sb.length() > 1 && TooLong()) {//如果头部包含信息过多,抛弃剩下的部分header.addHeaderString(sb.substring(0, sb.length() - 1));} else {break;}} while (true);}return header;}/*** * @param str*/private void addHeaderString(String str){str&#placeAll("r", "");header.add(str);if(str.startsWith("Host")){//解析主机和端口String[] hosts= str.split(":");host=hosts[1].trim();dsWith(METHOD_CONNECT)){port=hosts.length==3?hosts[2]:"443";//https默认端口为443}else dsWith(METHOD_GET)||dsWith(METHOD_POST)){port=hosts.length==3?hosts[2]:"80";//http默认端口为80}}}/*** 判定请求方式* @param str* @return*/private String addHeaderMethod(String str){str&#placeAll("r", "");header.add(str);if(str.startsWith(METHOD_CONNECT)){//https链接请求代理method=METHOD_CONNECT;}else if(str.startsWith(METHOD_GET)){//http GET请求method=METHOD_GET;}else if(str.startsWith(METHOD_POST)){//http POST请求method=METHOD_POST;}return method;}@Overridepublic String toString() {StringBuilder sb=new StringBuilder();for(String str : header){sb.append(str).append("rn");}sb.append("rn");String();}public boolean notTooLong(){return header.size()<=16;}public List<String> getHeader() {return header;}public void setHeader(List<String> header) {this.header = header;}public String getMethod() {return method;}public void setMethod(String method) {hod = method;}public String getHost() {return host;}public void setHost(String host) {this.host = host;}public String getPort() {return port;}public void setPort(String port) {this.port = port;}}

2、任务处理

/*** 将客户端发送过来的数据转发给请求的服务器端,并将服务器返回的数据转发给客户端**/
public class ProxyTask implements Runnable {private Socket socketIn;private Socket socketOut;private long totalUpload=0l;//总计上行比特数private long totalDownload=0l;//总计下行比特数public ProxyTask(Socket socket) {this.socketIn = socket;}private static final SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");/** 已连接到请求的服务器 */private static final String AUTHORED = "HTTP/1.1 200 Connection establishedrnrn";/** 本代理登陆失败(此应用暂时不涉及登陆操作) *///private static final String UNAUTHORED="HTTP/1.1 407 Unauthorizedrnrn";/** 内部错误 */private static final String SERVERERROR = "HTTP/1.1 500 Connection FAILEDrnrn";@Overridepublic void run() {StringBuilder builder=new StringBuilder();try {builder.append("rn").append("Request Time  :" + sdf.format(new Date()));InputStream isIn = InputStream();OutputStream osIn = OutputStream();//从客户端流数据中读取头部,获得请求主机和端口HttpHeader header = adHeader(isIn);//添加请求日志信息builder.append("rn").append("From    Host  :" + InetAddress());builder.append("rn").append("From    Port  :" + Port());builder.append("rn").append("Proxy   Method:" + Method());builder.append("rn").append("Request Host  :" + Host());builder.append("rn").append("Request Port  :" + Port());//如果没解析出请求请求地址和端口,则返回错误信息if (Host() == null || Port() == null) {osIn.Bytes());osIn.flush();return ;}// 查找主机和端口socketOut = new Host(), Integer.Port()));socketOut.setKeepAlive(true);InputStream isOut = InputStream();OutputStream osOut = OutputStream();//新开一个线程将返回的数据转发给客户端,串行会出问题,尚没搞明白原因Thread ot = new DataSendThread(isOut, osIn);ot.start();if (Method().equals(HttpHeader.METHOD_CONNECT)) {// 将已联通信号返回给请求页面osIn.Bytes());osIn.flush();}else{//http请求需要将请求头部也转发出去byte[] headerData&#String().getBytes();totalUpload+=headerData.length;osOut.write(headerData);osOut.flush();}//读取客户端请求过来的数据转发给服务器readForwardDate(isIn, osOut);//等待向客户端转发的线程结束ot.join();} catch (Exception e) {e.printStackTrace();if(!socketIn.isOutputShutdown()){//如果还可以返回错误状态的话,返回内部错误try {OutputStream().Bytes());} catch (IOException e1) {}}} finally {try {if (socketIn != null) {socketIn.close();}} catch (IOException e) {}if (socketOut != null) {try {socketOut.close();} catch (IOException e) {}}//纪录上下行数据量和最后结束时间并打印builder.append("rn").append("Up    Bytes  :" + totalUpload);builder.append("rn").append("Down  Bytes  :" + totalDownload);builder.append("rn").append("Closed Time  :" + sdf.format(new Date()));builder.append("rn");String());}	}/*** 避免多线程竞争把日志打串行了* @param msg*/private synchronized void logRequestMsg(String msg){System.out.println(msg);}/*** 读取客户端发送过来的数据,发送给服务器端* * @param isIn* @param osOut*/private void readForwardDate(InputStream isIn, OutputStream osOut) {byte[] buffer = new byte[4096];try {int len;while ((len = ad(buffer)) != -1) {if (len > 0) {osOut.write(buffer, 0, len);osOut.flush();}totalUpload+=len;if (socketIn.isClosed() || socketOut.isClosed()) {break;}}} catch (Exception e) {try {socketOut.close();// 尝试关闭远程服务器连接,中断转发线程的读阻塞状态} catch (IOException e1) {}}}/*** 将服务器端返回的数据转发给客户端* * @param isOut* @param osIn*/class DataSendThread extends Thread {private InputStream isOut;private OutputStream osIn;DataSendThread(InputStream isOut, OutputStream osIn) {this.isOut = isOut;this.osIn = osIn;}@Overridepublic void run() {byte[] buffer = new byte[4096];try {int len;while ((len = ad(buffer)) != -1) {if (len > 0) {// logData(buffer, 0, len);osIn.write(buffer, 0, len);osIn.flush();totalDownload+=len;}if (socketIn.isOutputShutdown() || socketOut.isClosed()) {break;}}} catch (Exception e) {}}}}

3、用线程池分发任务

/*** http 代理程序* @author lulaijun**/
public class SocketProxy {static final int listenPort=8002;public static void main(String[] args) throws Exception {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");ServerSocket serverSocket = new ServerSocket(listenPort);final ExecutorService tpe&#wCachedThreadPool();System.out.println("Proxy Server Start At "+sdf.format(new Date()));System.out.println("listening port:"+listenPort+"……");System.out.println();System.out.println();while (true) {Socket socket = null;try {socket = serverSocket.accept();socket.setKeepAlive(true);//加入任务列表,等待处理ute(new ProxyTask(socket));} catch (Exception e) {e.printStackTrace();}}}}



本文发布于:2024-01-29 02:05:10,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170646511311945.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:代理服务器   协议   代码   https   http
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23