分布式计算——实现简单的浏览器和web服务器
来源:互联网 发布:中外文电子期刊数据库 编辑:程序博客网 时间:2024/05/16 10:11
此次是分布式的第三次作业,作业要求如下:
1、基于TCP通讯(ServerSocket、Socket套接字),编写一个带有图形用户界面的浏览器和
一个支持文档读取并返回给客户浏览器的web服务器。客户端支持超链接事件处理,服务器采用多
线程技术支持并发访问。
2、在此基础上,修改服务器侧设计与实现,使之能够动态地添加客户端请求的类文件,即设计
一个小服务程序容器。
3、试在服务器侧代码中对客户端请求行、请求头和请求体部分进行处理。
====================================================================分割线
没有完成第3个要求。
客户端有两个类,一个是主类Client.java,
一个是浏览器类Browser.java。
Client.java代码如下:
Browser.java的代码如下:
package com.client;import java.io.IOException;public class Client {public static String request;public static void main(String[] args) throws IOException{Browser browser = new Browser();//生成浏览器对象browser.setBrowser();//调用setBrowser()方法初始化浏览器}}
Browser.java的代码如下:
package com.client;import java.awt.Button;import java.awt.Frame;import java.awt.TextField;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.io.*;import java.net.Socket;import javax.swing.*;import javax.swing.event.HyperlinkEvent;import javax.swing.event.HyperlinkListener;@SuppressWarnings("serial")public class Browser extends Frame implements HyperlinkListener {JEditorPane jEditorPane = new JEditorPane();//浏览器显示框String request = null;//定义字符串保存用户输入的请求//初始化浏览器框public void setBrowser() throws IOException {JFrame frame = new JFrame("浏览器");frame.setSize(800, 600);frame.setLocation(100, 50);frame.setLayout(null);frame.setResizable(false);jEditorPane.setEditable(false);jEditorPane.setContentType("text/html");//设置显示框的文本类型,使可以显示htmlJScrollPane jScrollPane = new JScrollPane(jEditorPane);//加一个滑动框jScrollPane.setSize(200, 200);jScrollPane.setLocation(100, 100);jScrollPane.setBounds(50, 100, 700, 450);jEditorPane.addHyperlinkListener(this);//添加超链接监听TextField textField = new TextField(50);textField.setBounds(200, 50, 320, 30);textField.setText("http://127.0.0.1:8080/");//初始化的时候添加访问地址和端口,不用重复输入Button button = new Button("前往");button.setBounds(550, 50, 70, 30);frame.add(textField);frame.add(button);frame.add(jScrollPane);myActionListener myActionListener = new myActionListener(textField);button.addActionListener(myActionListener);//在button上添加监听//给主frame上添加关闭按钮的功能frame.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {// TODO Auto-generated method stubSystem.exit(0);}});frame.setVisible(true);//设置可见}//处理文JEditPane中的超链接public void hyperlinkUpdate(HyperlinkEvent e){try{if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED){jEditorPane.setPage(e.getURL());//setPage方法可以直接获取连接内容}} catch (IOException e1) {e1.printStackTrace();}}//自定义监听类实现ActionListener接口class myActionListener implements ActionListener{TextField textField = new TextField();//将textField对象传进来,用以取用户的输入内容public myActionListener(TextField textField) {this.textField = textField;//获取到用户请求的url地址}//actionPerformed方法用以处理请求public void actionPerformed(ActionEvent e){//简单处理请求的url,将其处理成http请求行的样子 String url = textField.getText();url.trim();//去掉空格int beginindex = url.indexOf("//");url = url.substring(beginindex+2, url.length());beginindex = url.indexOf("/");url = url.substring(beginindex, url.length());request = "POST " + url + " HTTP/1.0\\r\\n";//设置请求try {getConnect();//连接服务器} catch (IOException e1) {e1.printStackTrace();}}}public void getConnect() throws IOException{Socket socket = new Socket("localhost", 8080);//new socket对象访问服务器socket.setSoTimeout(10000);//设置访问超时的时限,此处设置为10秒//获取一个输入流和一个输出流,并将两个流都包装起来OutputStream outputStream = socket.getOutputStream();PrintWriter socketOutput = new PrintWriter(new OutputStreamWriter(outputStream));InputStream inputStream = socket.getInputStream();BufferedReader socketInput = new BufferedReader(new InputStreamReader(inputStream));//将处理后的用户请求写入输出流,此时的请求格式为http的请求行的格式socketOutput.println(request);//将用户请求放入输出流中,传送给服务器socketOutput.flush();//----以上是处理发送请求到服务器的操作//----以下是处理服务器反馈的结果String responseline = new String();//保存每次从流中取出的信息String response = new String();//保存服务器返回的所有信息responseline = socketInput.readLine();//从流中读取一行内容 while(responseline != null){ System.out.println(responseline); response = response.concat(responseline); responseline = socketInput.readLine(); } jEditorPane.setText(response);//将服务器返回的内容写入浏览器中 jEditorPane.repaint();//重画一下浏览器的显示部分}}
客户端运行起来的样子会在最后演示。
--------------------------------------------------------------------------------------小分割线
服务器端写了五个类,分别是:
Server.java(主类)
MyServer.java(多线程服务器实现类)
Request.java(包装请求类)
Response.java(包装回复类)
ServletCon.java(ServletCon是servlet容器的意思。)
具体代码如下:
Server.java(主类):
package com.server;import java.io.IOException;public class Server {public static void main(String[] args) throws IOException{MyServer myserver = new MyServer(); //生成服务器对象}}
MyServer.java(多线程服务器实现类):
package com.server;import java.io.BufferedReader;import java.io.Closeable;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;import java.net.URL;import javax.servlet.ServletException;//此类实现Runnable接口,以实现多线程功能public class MyServer implements Runnable {int port = 8080;//定义监听端口ServerSocket serverSocket = null;//定义一个服务SocketSocket socket = null;//定义一个普通SocketString requestline = null;//定义一个字符串保存用户的请求行public MyServer() throws IOException{serverSocket = new ServerSocket(8080);//监听端口8080,参数为端口号System.out.println("Server服务已经启动。。。。");//while死循环监听请求,用线程去处理请求while(true){socket = serverSocket.accept();Thread thread = new Thread(this);//将当前对象作为线程参数thread.start();//启动线程,执行run()方法}}//重写run()方法public void run(){//定义一个输出流和一个输入流InputStream inputStream = null;OutputStream outputStream = null;try {inputStream = socket.getInputStream();//获取输入流outputStream = socket.getOutputStream();//获取输出流//通过Request的构造方法,将输入流传入,然后通过getUri就可以获取用户的请求,并会返回处理后的请求Request clientrequset = new Request(inputStream);//生成Request对象,将此流传入requestline = clientrequset.getUri();//调用getUri方法获取请求行中的路径//判断是请求页面还是请求servletif(requestline.startsWith("servlets/")){//如果是servlets请求,先将输入流传给Response对象Response responseservlet = new Response(outputStream);//此处生成servlet容器对象,用来处理servlet程序,需要将请求的内容传给servlet容器ServletCon servletCon = new ServletCon(requestline);try {//通过processServletRequest()方法处理用户请求,需要一个Request对象,和一个Response对象servletCon.processServletRequest(clientrequset, responseservlet);} catch (ServletException e) {e.printStackTrace();}System.out.println("处理servlet");}else{//如果是请求页面的话,将请求的内容通过setRequest()方法传给Response对象Response responsehtml = new Response(outputStream);//生成一个Response对象,并将输出流传入responsehtml.setRequest(requestline);//将请求对象传入responsehtml.sendStaticResource();//通过sendStaticResourct()方法将请求的页面返回给客户端System.out.println("处理html");}} catch (IOException e) {e.printStackTrace();}}}
Request.java(包装请求类),因为此类实现了ServletRequest接口,实现的一些方法没有用,
所以只给出需要用到的方法和扩展的方法:
package com.server;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.security.Principal;import java.util.Enumeration;import java.util.Locale;import java.util.Map;import javax.servlet.RequestDispatcher;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;public class Request implements ServletRequest{InputStream inputStream = null;//定义一个输入流,用来接收socket输入流的引用public static String clientrequest = new String();//保存用户请求行public Request(InputStream input) {this.inputStream = input;//获取输入流}//获取用户请求行中的uri标识public String getUri(){String requestString = new String();//保存uritry{BufferedReader socketInput = new BufferedReader(new InputStreamReader(inputStream));requestString = socketInput.readLine();//读取用户请求行,保存在requestString中clientrequest = requestString;//此处需要赋值一次,因为在Servlet程序中要用到requestString = this.parseUri(requestString);//调用parseUri处理用户请求行}catch(Exception e){e.printStackTrace();}return requestString;//将uri返回,用作比较}//处理用户请求行private String parseUri(String requestString){int beginindex = requestString.indexOf(" ");int endindex = requestString.lastIndexOf(" ");//因为请求行中的资源标识符在两个空格之间,所以取到两个空格的索引//取出资源定位符requestString = requestString.substring(beginindex+2, endindex);return requestString;//将定位符返回}...}
Response.java(包装回复类),此类同上,实现了ServletResponse接口,有些没用到的方法
就没有贴出来:
package com.server;import java.io.BufferedWriter;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.FileReader;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletOutputStream;import javax.servlet.ServletResponse;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Response implements ServletResponse{String requestline;//定义请求行字符串,用来保存用户请求OutputStream output = null;//定义一个输出流//通过构造方法 ,获取到输出流public Response(OutputStream output){this.output = output;}//处理客户的静态页面请求public void sendStaticResource() throws IOException{File responsehtml = new File(requestline);//生成用户请求页面对象//判断文件是否存在if(responsehtml.exists()){//存在的话,读取文件中的内容,并放到输出流中FileReader fileReader = new FileReader(responsehtml);PrintWriter socketOutput = this.getWriter();//读取文件内容,并写入输出流int i;while((i = fileReader.read()) != -1){socketOutput.print((char)i);//转换成char型}socketOutput.close();//关闭输出流}else{//如果不存在,则输出404PrintWriter socketOutput = this.getWriter();socketOutput.println("404 NotFound");socketOutput.close();//关闭输出流}}//获取请求行public void setRequest(String requestline){this.requestline = requestline;//获取到Request对象}//重写此方法public PrintWriter getWriter() throws IOException {return new PrintWriter(new OutputStreamWriter(output));}...}
ServletCon.java(ServletCon是servlet容器的意思。):
package com.server;import java.io.IOException;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletCon {ServletRequest request;ServletResponse response;String requestline;//通过构造方法获取到用户请求的内容public ServletCon(String requestline) {this.requestline = requestline;}//处理servlet请求public void processServletRequest(Request request, Response response) throws ServletException, IOException{this.request = request;//获取到Request对象this.response = response;//获取到Response对象String servletname = getServletName(requestline);//通过getServletName()方法获取到用户请求的类名Servlet servlet = loadServlet(servletname);//通过类名获取到对象的servlet程序servlet.service(request, response);//执行servlet的service方法}//通过servletname导入servlet程序private Servlet loadServlet(String servletname) throws ServletException, IOException {//此处的URL要定义到包名之外,不能连报名定义在一块URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:E:\\Eclipesworkspace\\fenbushi3\\bin") }); Servlet servlet = null; try { //此处注意在获取类文件的时候需要写全路径,也就是包含包名 Class servletClass = loader.loadClass("com.servlets."+servletname); servlet = (Servlet) servletClass.newInstance();//实例化一个对象 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return servlet; }//通过用户的请求行获取到请求的内容public String getServletName(String requestline){int beginindex = requestline.indexOf("/");int endindex = requestline.length();String servletname = requestline.substring(beginindex+1, endindex);return servletname;}}
------------------------------------------------------------------------------------------------------小分割线
以上内容就是服务器端和客户端的代码,接下来还有一个用户请求的html页面的代码
和一个servlet程序代码。
html页面代码:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><center><h1>this is a html page</h1></center></body></html>
servlet程序代码:
package com.servlets;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.server.Request;import com.server.Response;public class MyServlet extends HttpServlet{//重写service方法public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {Request request = (Request)req;//强制转化成子类对象String clientrequest = request.clientrequest;//获取到完整请求行//以下是获取到用户请求方式GET或者是POSTint beginindex = 0;int endindex = clientrequest.indexOf(" ");String requestmethod = clientrequest.substring(beginindex, endindex);//System.out.println(requestmethod);//根据不同的请求方式调用不用的方法,默认是POSTif(requestmethod.equals("POST")){doPost(req, res);}else if(requestmethod.equals("GET")){doGet(req, res);}}//重写doPost方法protected void doPost(ServletRequest req, ServletResponse res) throws ServletException, IOException {PrintWriter socketOutput = res.getWriter();//获取到输出流//输出一句HelloWorld到客户端socketOutput.println("<h1>");socketOutput.println("HelloWorld, I am servlet");socketOutput.println("</h1>");socketOutput.flush();//flush一下socketOutput.close();//关闭输出流}protected void doGet(ServletRequest req, ServletResponse res) throws ServletException, IOException {}}
====================================================================分割线
以上就是所有的代码,下面对运行的结果进行演示。
代码结构如下图:
启动服务器如下图:
客户端请求html页面和请求不存在的html页面如下图:
存在:
不存在:
请求servlet如下图:
====================================================================分割线
总结:
对于整个处理过程还没有完全吃透,还准备再看看,等差不多完全明白后,再来整理
一篇博文。这里面涉及到的知识点还会再回来整理,时间不多了,马上断电了,得赶紧保
存了。
对了,还没有测试多线程和网络中访问的情况,现在只是在本地可以执行。
1 0
- 分布式计算——实现简单的浏览器和web服务器
- 关于基于web浏览器实现分布式计算构想
- 简单的web服务器实现
- 实现简单的web服务器
- 实现简单的Web服务器
- 简单的web服务器实现
- 浏览器和WEB服务器建立TCP连接所消耗的时间计算 ?????????、
- tomcat——简单的Web服务器和Servlet容器
- Nodejs做web服务器的一个简单逻辑和实现
- 自己动手,写个Web服务器(Java版)——第一篇、浏览器和Web服务器的语言Http
- 实现简单的web浏览器--WebView
- 浏览器和服务器的交互简单原理
- web浏览器和web服务器的交互过程
- twisted 实现简单的web服务器
- 一个简单web服务器的实现
- 基于erlang的简单Web服务器实现
- C# | socket实现简单的web服务器
- 一个简单web服务器的java实现
- R学习-- R中的绘图命令练习
- 数据提取----httpclient,htmlparser,xpath
- Git 详解
- Ubuntu 16.04 切换Launcher位置
- 使用DPM训练自己的模型
- 分布式计算——实现简单的浏览器和web服务器
- 为什么创业者要假装读过《从0到1》和《创业维艰》?
- Javascript Web Design
- ECMAScript 5.1 Edition DOC 学习笔记
- 几种在shell命令行中过滤adb logcat输出的方法-[转]
- 调制信道与编码信道
- Scala--基础入门
- 栈的压入、弹出序列
- 两个.aspx 页面传值 Request.QueryString["NAME"]