java如何实现简单的http服务器

嵌入式设计应用

132人已加入

描述

  http

  超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。

  java

  Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

  Java具有简单性、面向对象、分布式、健壮性、安全性、平***立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。

  JAVA实现简易HTTP服务器

  搭建一个服务器,要能接收请求,并给浏览器返回正确响应。

  项目的下载地址

  项目目标:实现一个简易的多线程服务器,可以处理来自浏览器的请求(GET/POST),并做出正确的回应。

  请求分以下四种类型:

  1. 无参数,文本文件类型

  2. 无参数,图片文件类型

  3. 有参数,GET方式请求,并完成表单验证(登陆验证)

  4. 有参数,POST方式请求,并完成表单验证(登陆验证)

  首先,应该明确这个项目的基本实现原理,从浏览器读入用户请求的信息,服务器解析并记录返回的文件名和参数列表,如果文件存在,用流读取文件,并返回到浏览器上,如果不存在,返回相应的提示信息,参数列表和服务器存储的相同的话,返回登陆成功,否则返回失败。

  第一步,既然要解析从浏览器传过来的信息,那就要明白传过来信息的所使用的协议HTTP\UDP\FTP 和 URL的组成元素,因为是简易服务器,我们就只解析HTTP协议先。

  服务器

  Request是指从客户端到服务器端的请求消息

  Request 消息分为3部分,第一部分叫请求行, 第二部分叫http header, 第三部分是body. header和body之间有个空行,结构如下图

  服务器

  Method表示请求方法,比如”POST”,”GET”,

  Path-to-resoure表示请求的资源,

  Http/version-number 表示HTTP协议的版本号,

  当使用的是”GET” 方法的时候, body是为空的,当使用”POST”,body不为空,但是没有换行,readline()方法不能读

  Response是指服务器端到客户端的响应信息

  和Request消息的结构基本一样。 同样也分为三部分,第一部分叫request line, 第二部分叫request header,第三部分是body. header和body之间也有个空行, 结构如下图

  服务器

  状态码用来告诉HTTP客户端,HTTP服务器是否产生了预期的Response. HTTP/1.1中定义了5类状态码,1XX 提示信息 - 表示请求已被成功接收,继续处理;2XX 成功 - 表示请求已被成功接收,理解,接受;3XX 重定向 - 要完成请求必须进行更进一步的处理;4XX 客户端错误 - 请求有语法错误或请求无法实现;5XX 服务器端错误 - 服务器未能实现合法的请求,当然不写也是可以得,状态码就是便于程序员去分析当前页面是正确响应还是错误的。

  第二步,在了解URL和HTTP协议之后,就可以开始构建项目了。

  目前这个项目的UML图

  服务器

  第三步,准备文本、图片、HTML文件,然后开始编编编

  效果图:(端口号:23333)2333…

  默认访问

  服务器

  aaron.txt

  服务器

  a.jpg

  服务器

  GET/POST请求

  注意地址栏的变化

  login.html(GET)

  服务器

  login.html(GET) (登陆失败情况)

  服务器

  login.html(GET) (登陆成功情况)

  服务器

  login.html(POST)

  服务器

  login.html(POST) (登陆失败情况)

  服务器

  login.html(POST) (登陆成功情况)

  服务器

  部分源码:(全部源码去上面下载)

  //Server.java

  package cn.net.sight.server;

  import java.io.File;

  import java.io.FileInputStream;

  import java.io.FileNotFoundException;

  import java.io.IOException;

  import java.net.ServerSocket;

  import java.net.Socket;

  import java.util.Properties;

  import cn.net.sight.thread.ServerThread;

  public class Server {

  private static ServerSocket server;

  private static Properties properties;

  private int port;

  static {

  properties = new Properties();

  try {

  properties.load(new FileInputStream(new File(“src/resources/property.proterties”)));

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  //initialize the server

  public void init() {

  try {

  port = Integer.parseInt(properties.getProperty(“port”));

  server = new ServerSocket(port);

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  //receive the request from the web browser

  public void receive() {

  Socket clientSocket = new Socket();

  try {

  clientSocket = server.accept();

  } catch (IOException e) {

  e.printStackTrace();

  }

  ServerThread thread = new ServerThread(clientSocket);

  thread.start();

  try {

  thread.join();

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }

  //startup server

  public static void main(String[] args) {

  Server Aaroncat = new Server();

  Aaroncat.init();

  System.out.println(“----Aaroncat has startup----”);

  while(true){

  Aaroncat.receive();

  }

  }

  }

  //Request.java

  package cn.net.sight.server;

  import java.io.BufferedReader;

  import java.io.IOException;

  import java.io.InputStream;

  import java.io.InputStreamReader;

  import java.io.PrintStream;

  import java.net.Socket;

  import java.util.HashMap;

  import java.util.Map;

  import cn.net.sight.util.MessageUtil;

  public class Request {

  private InputStream input; // Socket --》 InputStream

  private Socket socket; // client --》 socket

  private BufferedReader buffer; // InputStream --》 BufferedReader

  private String schema; // the schema of the request GET or POST

  private String requestFileName; // exact file name

  private String requestData; // file name + 《key=value》。。。

  private String values_Str; // a string the user input in the form

  private int paramLength; // using in the POST: the length of parameters

  private Map《String, String》 socketValues;// values_str --》 MAP

  private PrintStream print;

  protected MessageUtil messageUtil = new MessageUtil();

  //省略了全部的setter() getter()

  private void doSchema(String firstLineInData) throws IOException {

  socketValues = new HashMap《String, String》();

  if (this.schema.equals(“GET”)) {

  // GET请求 --》 包含文件名和参数键值对

  // 实现了对FileName、SocketValues的赋值

  this.setRequestData(messageUtil.getRequestData(firstLineInData));

  if (this.requestData.contains(“?”)) {

  this.setRequestFileName(messageUtil.getFileName(this.getRequestData()));

  this.setSocketValues(messageUtil.getValues(this.getRequestData()));

  } else {

  // GET请求 --》只包含文件名

  // 实现了对FileName的赋值

  this.setRequestFileName(requestData);

  }

  } else {

  // POST请求 第一行只包含文件名

  // 实现了对FileName、SocketValues的赋值

  this.setRequestFileName(messageUtil.getRequestData(firstLineInData));

  this.getUserInfo(buffer);

  }

  }

  private void getUserInfo(BufferedReader br) throws IOException {

  while (this.buffer.ready()) {

  String remained = buffer.readLine();

  if (remained.contains(“Content-Length”)) {

  String[] temp = remained.split(“ ”);

  this.setParamLength(Integer.parseInt(temp[1]));

  break;

  }

  }

  buffer.readLine();

  String userInfo = “”;

  for (int i = 0; i 《 this.getParamLength(); i++) {

  userInfo += (char) buffer.read();

  }

  this.setValues_Str(userInfo);

  this.setSocketValues(messageUtil.getValues(this.getValues_Str()));

  }

  public Request(Socket clientSocket) throws IOException {

  this.setSocket(clientSocket);

  this.setPrint(new PrintStream(clientSocket.getOutputStream()));

  this.setInput(clientSocket.getInputStream());

  this.setBuffer(new BufferedReader(new InputStreamReader(clientSocket.getInputStream())));

  // get something from the first line

  String firstLineInData = buffer.readLine();

  this.setSchema(messageUtil.getSchema(firstLineInData)); // 获得请求方式Schema

  doSchema(firstLineInData); // 对Schema进行判断

  }

  }

  //Response.java

  package cn.net.sight.server;

  import java.io.IOException;

  import java.io.PrintStream;

  import java.net.Socket;

  import java.util.Date;

  import java.util.Map;

  import cn.net.sight.util.FileUtil;

  import cn.net.sight.util.LoginUtil;

  public class Response {

  private String fileName;

  private Map《String, String》 userValues;

  private PrintStream ps;

  private Request request;

  private Socket clientSocket;

  protected FileUtil fileUtil = new FileUtil();

  protected LoginUtil loginUtil = new LoginUtil();

  public String getFileName() {

  return fileName;

  }

  //省略了全部的setter() 和 getter()

  public Response(Request request) {

  this.setRequest(request);

  this.setClientSocket(request.getSocket());

  this.setFileName(request.getRequestFileName());

  userValues = this.request.getSocketValues();

  try {

  this.init();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  public void showup(String fileName) throws IOException {

  this.ps = this.request.getPrint();

  // 要处理正常文件名和空文件名

  if (!fileName.equals(“”) && !fileName.equals(“error.html”)) {

  this.ps.println(“HTTP/1.1 200 OK”);

  this.ps.println();

  fileUtil.readFile(fileName, ps);

  } else if (fileName.equals(“error.html”)) {

  ps.println(“HTTP/1.1 404 fileNotFound”);

  ps.println();

  fileUtil.readFile(“error.html”, ps);

  } else {

  ps.println(new Date().toString());

  }

  if (ps != null){

  ps.close();

  }

  }

  public void init() throws IOException {

  //如果信息MAP是空,则代表是普通文件或者是默认访问

  if (userValues.isEmpty()) {

  if (fileName != “”) {

  this.showup(fileName);

  } else {

  this.ps = this.request.getPrint();

  ps.println(new Date().toString());

  if(ps != null) ps.close();

  if(clientSocket != null)clientSocket.close();

  }

  } else {

  //如果信息MAP不为空,代表是GET/POST请求,并带有参数键值对

  this.Check(userValues, fileName);

  }

  }

  public void Check(Map《String, String》 values_list, String respFileName) throws IOException {

  // 验证用户输入信息的合法性

  if (loginUtil.isValid(values_list)) {

  this.showup(respFileName);

  } else {

  this.showup(“error.html”);

  }

  }

  }

  //ServerThread.java

  package cn.net.sight.thread;

  import java.io.IOException;

  import java.net.Socket;

  import cn.net.sight.server.Response;

  import cn.net.sight.server.Request;

  public class ServerThread extends Thread {

  private Socket clientSocket;

  private Request request;

  private Response response;

  public ServerThread() {

  super();

  }

  public ServerThread(Socket clientSocket) {

  super();

  this.clientSocket = clientSocket;

  }

  public Socket getClientSocket() {

  return clientSocket;

  }

  public void setClientSocket(Socket clientSocket) {

  this.clientSocket = clientSocket;

  }

  public Request getRequest() {

  return request;

  }

  public void setRequest(Request request) {

  this.request = request;

  }

  public Response getResponse() {

  return response;

  }

  public void setResponse(Response response) {

  this.response = response;

  }

  public void run(){

  super.run();

  try {

  this.setRequest(new Request(clientSocket));

  this.response = new Response(request);

  this.setResponse(response);

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  }

  //FileUtil.java

  package cn.net.sight.util;

  import java.io.File;

  import java.io.FileInputStream;

  import java.io.FileNotFoundException;

  import java.io.IOException;

  import java.io.PrintStream;

  public class FileUtil {

  private static final int BUFFER_SIZE = 1024;

  public void readFile(String file_Name, PrintStream ps) throws IOException {

  byte[] buffer = new byte[BUFFER_SIZE];

  int length;

  File file = new File(“src/resources/” + file_Name);

  FileInputStream fis = null;

  if (file.exists()) {

  try {

  fis = new FileInputStream(file);

  while ((length = fis.read(buffer)) != -1) {

  ps.write(buffer, 0, length);

  ps.flush();

  }

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  }

  } else {

  ps.println(“File not found”);

  ps.println();

  }

  }

  }

  //LoginUtil.java

  package cn.net.sight.util;

  import java.io.File;

  import java.io.FileInputStream;

  import java.io.FileNotFoundException;

  import java.io.IOException;

  import java.util.Map;

  import java.util.Properties;

  public class LoginUtil {

  protected boolean flag = false;

  protected Map《String, String》 values;

  private static Properties properties;

  static {

  properties = new Properties();

  try {

  properties.load(new FileInputStream(new File(“src/resources/property.proterties”)));

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  public boolean isFlag() {

  return flag;

  }

  public void setFlag(boolean flag) {

  this.flag = flag;

  }

  public Map《String, String》 getValues() {

  return values;

  }

  public void setValues(Map《String, String》 values) {

  this.values = values;

  }

  // 验证用户信息的合法性(应用JDBC桥,连接数据库)

  public boolean isValid(Map《String, String》 values) {

  String username = properties.getProperty(“username”);

  String password = properties.getProperty(“password”);

  if (values.get(“username”).equals(username)) {

  if (values.get(“password”).equals(password)) {

  flag = true;

  System.out.println(“The user ” + values.get(“username”) + “ was log the server.”);

  return flag;

  }

  } else {

  System.out.println(“Forbide the ” + values.get(“username”) + “ log the server”);

  return flag;

  }

  return false;

  }

  }

  //MessageUtil.java

  package cn.net.sight.util;

  import java.util.HashMap;

  import java.util.Map;

  public class MessageUtil {

  // schema : GET or POST

  public String getSchema(String requestMsg) {

  String[] result = new String[1];

  if (requestMsg.contains(“ ”)) {

  result = requestMsg.split(“ ”);

  requestMsg = result[0];

  }

  return requestMsg;

  }

  // get the resquestData = (filename + map《S,S》)

  public String getRequestData(String firstLineInData) {

  String[] result = new String[10];

  result = firstLineInData.split(“ ”);

  firstLineInData = result[1].substring(1);

  return firstLineInData;

  }

  // get the filename from the requestData

  public String getFileName(String requestData) {

  String[] result = new String[10];

  result = requestData.split(“[?]”);

  return result[0];

  }

  // save the info into the map《S,S》

  public Map《String, String》 getValues(String requestData) {

  Map《String, String》 values = new HashMap《String, String》();

  String[] result = new String[10];

  String regex = “[&=]”;

  if (requestData.contains(“?”)) {

  result = requestData.split(“[?]”);

  String data_List = result[1];

  result = data_List.split(regex);

  for (int i = 0; i 《 result.length - 1; i += 2) {

  values.put(result[i], result[i + 1]);

  }

  return values;

  } else {

  result = requestData.split(regex);

  for (int i = 0; i 《 result.length - 1; i += 2) {

  values.put(result[i], result[i + 1]);

  }

  return values;

  }

  }

  }

  整个项目结构

  服务器

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分