1、使用socket简单实现http协议:
//参考链接:http://blog.csdn.net/sunxing007/article/details/4305956
- import java.io.*;
- import java.net.*;
- /**
- * MyHttpServer 实现一个简单的HTTP服务器端,可以获取用户提交的内容
- * 并给用户一个response
- * 因为时间的关系,对http头的处理显得不规范
- * 对于上传附件,暂时只能解析只上传一个附件而且附件位置在第一个的情况
- * 转载请注明来自http://blog.csdn.net/sunxing007
- *
- * http://blog.csdn.net/sunxing007/article/details/4305956
- * **/
- public class MyHttpServer {
- //服务器根目录,post.html, upload.html都放在该位置
- public static String WEB_ROOT = "c:/root";
- //端口
- private int port;
- //用户请求的文件的url
- private String requestPath;
- //mltipart/form-data方式提交post的分隔符,
- private String boundary = null;
- //post提交请求的正文的长度
- private int contentLength = 0;
- public MyHttpServer(String root, int port) {
- WEB_ROOT = root;
- this.port = port;
- requestPath = null;
- }
- //处理GET请求
- private void doGet(DataInputStream reader, OutputStream out) throws Exception {
- if (new File(WEB_ROOT + this.requestPath).exists()) {
- //从服务器根目录下找到用户请求的文件并发送回浏览器
- InputStream fileIn = new FileInputStream(WEB_ROOT + this.requestPath);
- byte[] buf = new byte[fileIn.available()];
- fileIn.read(buf);
- out.write(buf);
- out.close();
- fileIn.close();
- reader.close();
- System.out.println("request complete.");
- }
- }
- //处理post请求
- private void doPost(DataInputStream reader, OutputStream out) throws Exception {
- String line = reader.readLine();
- while (line != null) {
- System.out.println(line);
- line = reader.readLine();
- if ("".equals(line)) {
- break;
- } else if (line.indexOf("Content-Length") != -1) {
- this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
- }
- //表明要上传附件, 跳转到doMultiPart方法。
- else if(line.indexOf("multipart/form-data")!= -1){
- //得multiltipart的分隔符
- this.boundary = line.substring(line.indexOf("boundary") + 9);
- this.doMultiPart(reader, out);
- return;
- }
- }
- //继续读取普通post(没有附件)提交的数据
- System.out.println("begin reading posted data......");
- String dataLine = null;
- //用户发送的post数据正文
- byte[] buf = {};
- int size = 0;
- if (this.contentLength != 0) {
- buf = new byte[this.contentLength];
- while(size<this.contentLength){
- int c = reader.read();
- buf[size++] = (byte)c;
- }
- System.out.println("The data user posted: " + new String(buf, 0, size));
- }
- //发送回浏览器的内容
- String response = "";
- response += "HTTP/1.1 200 OK/n";
- response += "Server: Sunpache 1.0/n";
- response += "Content-Type: text/html/n";
- response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT/n";
- response += "Accept-ranges: bytes";
- response += "/n";
- String body = "<html><head><title>test server</title></head><body><p>post ok:</p>" + new String(buf, 0, size) + "</body></html>";
- System.out.println(body);
- out.write(response.getBytes());
- out.write(body.getBytes());
- out.flush();
- reader.close();
- out.close();
- System.out.println("request complete.");
- }
- //处理附件
- private void doMultiPart(DataInputStream reader, OutputStream out) throws Exception {
- System.out.println("doMultiPart ......");
- String line = reader.readLine();
- while (line != null) {
- System.out.println(line);
- line = reader.readLine();
- if ("".equals(line)) {
- break;
- } else if (line.indexOf("Content-Length") != -1) {
- this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
- System.out.println("contentLength: " + this.contentLength);
- } else if (line.indexOf("boundary") != -1) {
- //获取multipart分隔符
- this.boundary = line.substring(line.indexOf("boundary") + 9);
- }
- }
- System.out.println("begin get data......");
- /*下面的注释是一个浏览器发送带附件的请求的全文,所有中文都是说明性的文字*****
- <HTTP头部内容略>
- ............
- Cache-Control: no-cache
- <这里有一个空行,表明接下来的内容都是要提交的正文>
- -----------------------------7d925134501f6<这是multipart分隔符>
- Content-Disposition: form-data; name="myfile"; filename="mywork.doc"
- Content-Type: text/plain
- <附件正文>........................................
- .................................................
- -----------------------------7d925134501f6<这是multipart分隔符>
- Content-Disposition: form-data; name="myname"<其他字段或附件>
- <这里有一个空行>
- <其他字段或附件的内容>
- -----------------------------7d925134501f6--<这是multipart分隔符,最后一个分隔符多两个->
- ****************************************************************/
- /**
- * 上面的注释是一个带附件的multipart类型的POST的全文模型,
- * 要把附件去出来,就是要找到附件正文的起始位置和结束位置
- * **/
- if (this.contentLength != 0) {
- //把所有的提交的正文,包括附件和其他字段都先读到buf.
- byte[] buf = new byte[this.contentLength];
- int totalRead = 0;
- int size = 0;
- while (totalRead < this.contentLength) {
- size = reader.read(buf, totalRead, this.contentLength - totalRead);
- totalRead += size;
- }
- //用buf构造一个字符串,可以用字符串方便的计算出附件所在的位置
- String dataString = new String(buf, 0, totalRead);
- System.out.println("the data user posted:/n" + dataString);
- int pos = dataString.indexOf(boundary);
- //以下略过4行就是第一个附件的位置
- pos = dataString.indexOf("/n", pos) + 1;
- pos = dataString.indexOf("/n", pos) + 1;
- pos = dataString.indexOf("/n", pos) + 1;
- pos = dataString.indexOf("/n", pos) + 1;
- //附件开始位置
- int start = dataString.substring(0, pos).getBytes().length;
- pos = dataString.indexOf(boundary+"--", pos) - 4;
- //附件结束位置
- int end = dataString.substring(0, pos).getBytes().length;
- //以下找出filename
- int fileNameBegin = dataString.indexOf("filename") + 10;
- int fileNameEnd = dataString.indexOf("/n", fileNameBegin);
- String fileName = dataString.substring(fileNameBegin, fileNameEnd);
- /**
- * 有时候上传的文件显示完整的文件名路径,比如c:/my file/somedir/project.doc
- * 但有时候只显示文件的名字,比如myphoto.jpg.
- * 所以需要做一个判断。
- */
- if(fileName.lastIndexOf("//")!=-1){
- fileName = fileName.substring(fileName.lastIndexOf("//") + 1);
- }
- fileName = fileName.substring(0, fileName.length()-2);
- OutputStream fileOut = new FileOutputStream("c://" + fileName);
- fileOut.write(buf, start, end-start);
- fileOut.close();
- fileOut.close();
- }
- String response = "";
- response += "HTTP/1.1 200 OK/n";
- response += "Server: Sunpache 1.0/n";
- response += "Content-Type: text/html/n";
- response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT/n";
- response += "Accept-ranges: bytes";
- response += "/n";
- out.write("<html><head><title>test server</title></head><body><p>Post is ok</p></body></html>".getBytes());
- out.flush();
- reader.close();
- System.out.println("request complete.");
- }
- public void service() throws Exception {
- ServerSocket serverSocket = new ServerSocket(this.port);
- System.out.println("server is ok.");
- //开启serverSocket等待用户请求到来,然后根据请求的类别作处理
- //在这里我只针对GET和POST作了处理
- //其中POST具有解析单个附件的能力
- while (true) {
- try {
- Socket socket = serverSocket.accept();
- System.out.println("new request coming.");
- DataInputStream reader = new DataInputStream((socket.getInputStream()));
- String line = reader.readLine();
- if(line!=null){
- String method = line.substring(0, 4).trim();
- OutputStream out = socket.getOutputStream();
- this.requestPath = line.split(" ")[1];
- System.out.println(method);
- if ("GET".equalsIgnoreCase(method)) {
- System.out.println("do get......");
- this.doGet(reader, out);
- } else if ("POST".equalsIgnoreCase(method)) {
- System.out.println("do post......");
- this.doPost(reader, out);
- }
- }else{
- System.err.println("line is null!");
- }
- socket.close();
- System.out.println("socket closed.");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String args[]) throws Exception {
- MyHttpServer server = new MyHttpServer("c:/root", 8080);
- server.service();
- }
- }
2、使用jdk自导的httpserver组件
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.InetSocketAddress;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Set;
- import java.util.concurrent.Executors;
- import com.sun.net.httpserver.Headers;
- import com.sun.net.httpserver.HttpExchange;
- import com.sun.net.httpserver.HttpHandler;
- import com.sun.net.httpserver.HttpServer;
- //在eclipse中会出现Access restriction: The type Headers is not accessible due to restriction on required library
- //解决办法:把Windows-Preferences-Java-Complicer- Errors/Warnings里面的Deprecated and restricted API中的Forbidden references(access rules)选为Warning就可以编译通过。
- /**
- * 使用jdk自带sun httpserver组件构建Http服务器,
- * JDK自带的HttpServer是一个非常轻量级的Http服务端框架,但是它非常灵活,易于扩展,
- * @author Administrator
- *
- */
- public class HttpServerDemo {
- public static void main(String[] args) throws IOException {
- InetSocketAddress addr = new InetSocketAddress(8080);
- HttpServer server = HttpServer.create(addr, 0);
- server.createContext("/", new MyHandler());
- server.setExecutor(Executors.newCachedThreadPool());
- server.start();
- System.out.println("Server is listening on port 8080");
- }
- }
- class MyHandler implements HttpHandler {
- public void handle(HttpExchange exchange) throws IOException {
- String requestMethod = exchange.getRequestMethod();
- System.out.println("处理新请求:"+requestMethod);
- if (requestMethod.equalsIgnoreCase("GET")) {
- Headers responseHeaders = exchange.getResponseHeaders();
- responseHeaders.set("Content-Type", "text/plain");
- exchange.sendResponseHeaders(200, 0);
- OutputStream responseBody = exchange.getResponseBody();
- Headers requestHeaders = exchange.getRequestHeaders();
- Set<String> keySet = requestHeaders.keySet();
- Iterator<String> iter = keySet.iterator();
- while (iter.hasNext()) {
- String key = iter.next();
- List values = requestHeaders.get(key);
- String s = key + " = " + values.toString() + "\n";
- responseBody.write(s.getBytes());
- }
- responseBody.close();
- }
- }
- }
3、使用apache开源的httpcore组件实现。
- /*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
- package org.apache.http.examples;
- import java.io.File;
- import java.io.IOException;
- import java.io.InterruptedIOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.net.URL;
- import java.net.URLDecoder;
- import java.nio.charset.Charset;
- import java.security.KeyStore;
- import java.util.Locale;
- import org.apache.http.ConnectionClosedException;
- import org.apache.http.HttpConnectionFactory;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpEntityEnclosingRequest;
- import org.apache.http.HttpException;
- import org.apache.http.HttpRequest;
- import org.apache.http.HttpResponse;
- import org.apache.http.HttpServerConnection;
- import org.apache.http.HttpStatus;
- import org.apache.http.MethodNotSupportedException;
- import org.apache.http.entity.ContentType;
- import org.apache.http.entity.FileEntity;
- import org.apache.http.entity.StringEntity;
- import org.apache.http.impl.DefaultBHttpServerConnection;
- import org.apache.http.impl.DefaultBHttpServerConnectionFactory;
- import org.apache.http.protocol.BasicHttpContext;
- import org.apache.http.protocol.HttpContext;
- import org.apache.http.protocol.HttpProcessor;
- import org.apache.http.protocol.HttpProcessorBuilder;
- import org.apache.http.protocol.HttpRequestHandler;
- import org.apache.http.protocol.HttpService;
- import org.apache.http.protocol.ResponseConnControl;
- import org.apache.http.protocol.ResponseContent;
- import org.apache.http.protocol.ResponseDate;
- import org.apache.http.protocol.ResponseServer;
- import org.apache.http.protocol.UriHttpRequestHandlerMapper;
- import org.apache.http.util.EntityUtils;
- import javax.net.ssl.KeyManager;
- import javax.net.ssl.KeyManagerFactory;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLServerSocketFactory;
- /**
- * Basic, yet fully functional and spec compliant, HTTP/1.1 file server.
- */
- public class ElementalHttpServer {
- public static void main(String[] args) throws Exception {
- /**
- if (args.length < 1) {
- System.err.println("Please specify document root directory");
- System.exit(1);
- }
- // Document root directory
- String docRoot = args[0];*/
- String docRoot="c:/root";
- int port = 8080;
- if (args.length >= 2) {
- port = Integer.parseInt(args[1]);
- }
- // Set up the HTTP protocol processor
- HttpProcessor httpproc = HttpProcessorBuilder.create()
- .add(new ResponseDate())
- .add(new ResponseServer("Test/1.1"))
- .add(new ResponseContent())
- .add(new ResponseConnControl()).build();
- // Set up request handlers
- UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
- reqistry.register("*", new HttpFileHandler(docRoot));
- // Set up the HTTP service
- HttpService httpService = new HttpService(httpproc, reqistry);
- SSLServerSocketFactory sf = null;
- if (port == 8443) {
- // Initialize SSL context
- ClassLoader cl = ElementalHttpServer.class.getClassLoader();
- URL url = cl.getResource("my.keystore");
- if (url == null) {
- System.out.println("Keystore not found");
- System.exit(1);
- }
- KeyStore keystore = KeyStore.getInstance("jks");
- keystore.load(url.openStream(), "secret".toCharArray());
- KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
- KeyManagerFactory.getDefaultAlgorithm());
- kmfactory.init(keystore, "secret".toCharArray());
- KeyManager[] keymanagers = kmfactory.getKeyManagers();
- SSLContext sslcontext = SSLContext.getInstance("TLS");
- sslcontext.init(keymanagers, null, null);
- sf = sslcontext.getServerSocketFactory();
- }
- Thread t = new RequestListenerThread(port, httpService, sf);
- t.setDaemon(false);
- t.start();
- }
- static class HttpFileHandler implements HttpRequestHandler {
- private final String docRoot;
- public HttpFileHandler(final String docRoot) {
- super();
- this.docRoot = docRoot;
- }
- public void handle(
- final HttpRequest request,
- final HttpResponse response,
- final HttpContext context) throws HttpException, IOException {
- String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
- if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
- throw new MethodNotSupportedException(method + " method not supported");
- }
- String target = request.getRequestLine().getUri();
- if (request instanceof HttpEntityEnclosingRequest) {
- HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
- byte[] entityContent = EntityUtils.toByteArray(entity);
- System.out.println("Incoming entity content (bytes): " + entityContent.length);
- }
- final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
- if (!file.exists()) {
- response.setStatusCode(HttpStatus.SC_NOT_FOUND);
- StringEntity entity = new StringEntity(
- "<html><body><h1>File" + file.getPath() +
- " not found</h1></body></html>",
- ContentType.create("text/html", "UTF-8"));
- response.setEntity(entity);
- System.out.println("File " + file.getPath() + " not found");
- } else if (!file.canRead() || file.isDirectory()) {
- response.setStatusCode(HttpStatus.SC_FORBIDDEN);
- StringEntity entity = new StringEntity(
- "<html><body><h1>Access denied</h1></body></html>",
- ContentType.create("text/html", "UTF-8"));
- response.setEntity(entity);
- System.out.println("Cannot read file " + file.getPath());
- } else {
- response.setStatusCode(HttpStatus.SC_OK);
- FileEntity body = new FileEntity(file, ContentType.create("text/html", (Charset) null));
- response.setEntity(body);
- System.out.println("Serving file " + file.getPath());
- }
- }
- }
- static class RequestListenerThread extends Thread {
- private final HttpConnectionFactory<DefaultBHttpServerConnection> connFactory;
- private final ServerSocket serversocket;
- private final HttpService httpService;
- public RequestListenerThread(
- final int port,
- final HttpService httpService,
- final SSLServerSocketFactory sf) throws IOException {
- this.connFactory = DefaultBHttpServerConnectionFactory.INSTANCE;
- this.serversocket = sf != null ? sf.createServerSocket(port) : new ServerSocket(port);
- this.httpService = httpService;
- }
- @Override
- public void run() {
- System.out.println("Listening on port " + this.serversocket.getLocalPort());
- while (!Thread.interrupted()) {
- try {
- // Set up HTTP connection
- Socket socket = this.serversocket.accept();
- System.out.println("Incoming connection from " + socket.getInetAddress());
- HttpServerConnection conn = this.connFactory.createConnection(socket);
- // Start worker thread
- Thread t = new WorkerThread(this.httpService, conn);
- t.setDaemon(true);
- t.start();
- } catch (InterruptedIOException ex) {
- break;
- } catch (IOException e) {
- System.err.println("I/O error initialising connection thread: "
- + e.getMessage());
- break;
- }
- }
- }
- }
- static class WorkerThread extends Thread {
- private final HttpService httpservice;
- private final HttpServerConnection conn;
- public WorkerThread(
- final HttpService httpservice,
- final HttpServerConnection conn) {
- super();
- this.httpservice = httpservice;
- this.conn = conn;
- }
- @Override
- public void run() {
- System.out.println("New connection thread");
- HttpContext context = new BasicHttpContext(null);
- try {
- while (!Thread.interrupted() && this.conn.isOpen()) {
- this.httpservice.handleRequest(this.conn, context);
- }
- } catch (ConnectionClosedException ex) {
- System.err.println("Client closed connection");
- } catch (IOException ex) {
- System.err.println("I/O error: " + ex.getMessage());
- } catch (HttpException ex) {
- System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
- } finally {
- try {
- this.conn.shutdown();
- } catch (IOException ignore) {}
- }
- }
- }
- }