博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA编写HTTP代码并发布在网上
阅读量:4183 次
发布时间:2019-05-26

本文共 21550 字,大约阅读时间需要 71 分钟。

   最近在学习JAVA网络编程编写HTTP服务器,HTTP是个大协议,完整功能的HTTP服务器必须响应资源请求,将URL转换为本地系统的资源名。响应各种形式的HTTP请求(GET、POST等)。处理不存在的文件请求,返回各种形式的状态码,解析MIME类型等。但许多特定功能的HTTP服务器并不需要所有这些功能。因此可用JAVA编写一个代替

首先来看利用的云服务器,选择的是新浪SAE,因为他免费,方便。

创建应用

在语言上选择JAVA

创建完成后进入代码管理

将编写好的代码打包成WAR 上传

这里可以选择用Myeclipise打包 

首先需要注意的是,MyEclipse只能对WebProject类型的工程进行WAR包制作,对于我们常用的JavaProject则无法进行WAR包制作。

打开MyEclipse,在【Package Explorer】中选中需要压缩的项目,点击工具栏中的“File->Export…”,在弹出的【Export】对话框上,点击选中树状图中的“J2EE->WAR file  (MyEclipse)”,点击【Next  >】继续

在【WAR Export】对话框上选择需要压缩的项目名称,点击【Browse…】,在弹出的【另存为】对话框上选择WAR包保存的路径和名称,确认后点击【Finish】,开始进行压缩。

这里也可以用SVN进行代码的上传 不做说明

上传成功后就可以点击链接通过HTTP访问了

最后我们来看下代码:

1.AcceptHanlder.java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;public class AcceptHandler implements Handler {  public void handle(SelectionKey key) throws IOException {    ServerSocketChannel serverSocketChannel=(ServerSocketChannel)key.channel();    SocketChannel socketChannel = serverSocketChannel.accept();    if (socketChannel== null)return;    System.out.println("接收到客户连接,来自:" +                   socketChannel.socket().getInetAddress() +                   ":" + socketChannel.socket().getPort());    ChannelIO cio =new ChannelIO(socketChannel, false/*非阻塞模式*/);    RequestHandler rh = new RequestHandler(cio);    socketChannel.register(key.selector(), SelectionKey.OP_READ, rh);  }}
2.ChannelIO.java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;public class ChannelIO {  protected SocketChannel socketChannel;  protected ByteBuffer requestBuffer;  private static int requestBufferSize = 4096;  public ChannelIO(SocketChannel socketChannel, boolean blocking)    throws IOException {    this.socketChannel = socketChannel;    socketChannel.configureBlocking(blocking); //设置阻塞模式    requestBuffer = ByteBuffer.allocate(requestBufferSize);  }  public SocketChannel getSocketChannel() {    return socketChannel;  }  /*   * 如果原缓冲区的剩余容量不够,就创建一个新的缓冲区,容量为原来的两倍,   * 把原来缓冲区的数据拷贝到新缓冲区   */  protected void resizeRequestBuffer(int remaining) {    if (requestBuffer.remaining() < remaining) {      // 把容量增大到原来的两倍      ByteBuffer bb = ByteBuffer.allocate(requestBuffer.capacity() * 2);      requestBuffer.flip();      bb.put(requestBuffer);  //把原来缓冲区中的数据拷贝到新的缓冲区      requestBuffer = bb;    }  }  /*   * 接收数据,把它们存放到requestBuffer中,如果requsetBuffer的剩余容量不足5%,   * 就调用resizeRequestBuffer()方法扩充容量   */  public int read() throws IOException {    resizeRequestBuffer(requestBufferSize/20);    return socketChannel.read(requestBuffer);  }  /*   * 返回requestBuffer,它存放了所有的请求数据   */  public ByteBuffer getReadBuf() {      return requestBuffer;  }  /*   * 发送参数指定的ByteBuffer中的数据   */  public int write(ByteBuffer src) throws IOException {    return socketChannel.write(src);  }  /*   * 把FileChannel中的数据写到SocketChannel中   */  public long transferTo(FileChannel fc, long pos, long len) throws IOException {    return fc.transferTo(pos, len, socketChannel);  }  /*   * 关闭SocketChannel   */  public void close() throws IOException {    socketChannel.close();  }}
3.Content.java

package Test;/** * 表示服务器发送给客户的正文内容 */public interface Content extends Sendable {  //内容的类型  String type();  //在内容还没有准备之前,即还没有调用prepare()方法之前,length()方法返回-1。  long length();}
4.FileContent.java

package Test;import java.io.*;import java.net.*;import java.nio.channels.*;import java.nio.charset.*;/*文件形式的响应正文*/public class FileContent implements Content {  //假定文件的根目录为"root"  private static File ROOT = new File("D:\\");    private File file;  public FileContent(URI uri) {    file = new File(ROOT,                  uri.getPath()                  .replace('/',File.separatorChar));  }  private String type = null;  /* 确定文件类型 */  public String type() {    if (type != null) return type;    String nm = file.getName();    if (nm.endsWith(".html")|| nm.endsWith(".htm"))        type = "text/html; charset=GBK";  //HTML网页    else if ((nm.indexOf('.') < 0) || nm.endsWith(".txt"))        type = "text/plain; charset=GBK";  //文本文件    else        type = "application/octet-stream";  //应用程序    return type;  }  private FileChannel fileChannel = null;  private long length = -1;  //文件长度  private long position = -1; //文件的当前位置  public long length() {      return length;  }  /* 创建FileChannel对象*/  public void prepare() throws IOException {    if (fileChannel == null)        fileChannel = new RandomAccessFile(file, "r").getChannel();    length = fileChannel.size();    position = 0;  }  /* 发送正文,如果发送完毕,就返回false,否则返回true */  public boolean send(ChannelIO channelIO) throws IOException {    if (fileChannel == null)        throw new IllegalStateException();    if (position < 0)        throw new IllegalStateException();    if (position >= length) {        return false;  //如果发送完毕,就返回false    }    position += channelIO.transferTo(fileChannel, position, length - position);    return (position < length);  }  public void release() throws IOException {    if (fileChannel != null){        fileChannel.close();  //关闭fileChannel        fileChannel = null;    }  }}
5.Hanlder.java

package Test;import java.io.*;import java.nio.channels.*;public interface Handler {    public void handle(SelectionKey key) throws IOException;}
6.HttpServer.java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;import java.net.*;import java.util.*;public class HttpServer{  private Selector selector = null;  private ServerSocketChannel serverSocketChannel = null;  private int port = 80;  private Charset charset=Charset.forName("GBK");  public HttpServer()throws IOException{    selector = Selector.open();    serverSocketChannel= ServerSocketChannel.open();    serverSocketChannel.socket().setReuseAddress(true);    serverSocketChannel.configureBlocking(false);    serverSocketChannel.socket().bind(new InetSocketAddress(port));    System.out.println("服务器启动");  }  public void service() throws IOException{    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT,new AcceptHandler());    for(;;){      int n = selector.select();      if(n==0)continue;      Set readyKeys = selector.selectedKeys();      Iterator it = readyKeys.iterator();      while (it.hasNext()){        SelectionKey key=null;        try{            key = (SelectionKey) it.next();            it.remove();  	    final Handler handler = (Handler)key.attachment();            handler.handle(key);        }catch(IOException e){           e.printStackTrace();           try{               if(key!=null){                   key.cancel();                   key.channel().close();               }           }catch(Exception ex){e.printStackTrace();}        }      }//#while    }//#while  }  public static void main(String args[])throws Exception{    final HttpServer server = new HttpServer();    server.service();  }}
7.MalformedRequestException.java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;import java.net.*;import java.util.*;public class HttpServer{  private Selector selector = null;  private ServerSocketChannel serverSocketChannel = null;  private int port = 80;  private Charset charset=Charset.forName("GBK");  public HttpServer()throws IOException{    selector = Selector.open();    serverSocketChannel= ServerSocketChannel.open();    serverSocketChannel.socket().setReuseAddress(true);    serverSocketChannel.configureBlocking(false);    serverSocketChannel.socket().bind(new InetSocketAddress(port));    System.out.println("服务器启动");  }  public void service() throws IOException{    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT,new AcceptHandler());    for(;;){      int n = selector.select();      if(n==0)continue;      Set readyKeys = selector.selectedKeys();      Iterator it = readyKeys.iterator();      while (it.hasNext()){        SelectionKey key=null;        try{            key = (SelectionKey) it.next();            it.remove();  	    final Handler handler = (Handler)key.attachment();            handler.handle(key);        }catch(IOException e){           e.printStackTrace();           try{               if(key!=null){                   key.cancel();                   key.channel().close();               }           }catch(Exception ex){e.printStackTrace();}        }      }//#while    }//#while  }  public static void main(String args[])throws Exception{    final HttpServer server = new HttpServer();    server.service();  }}
8.Request.java
package Test;import java.net.*;import java.nio.*;import java.nio.charset.*;import java.util.regex.*;/* 代表客户的HTTP请求 */public class Request {  static class Action {  //枚举类,表示HTTP请求方式    private String name;    private Action(String name) { this.name = name; }    public String toString() { return name; }    static Action GET = new Action("GET");    static Action PUT = new Action("PUT");    static Action POST = new Action("POST");    static Action HEAD = new Action("HEAD");    public static Action parse(String s) {        if (s.equals("GET"))            return GET;        if (s.equals("PUT"))            return PUT;        if (s.equals("POST"))            return POST;        if (s.equals("HEAD"))            return HEAD;        throw new IllegalArgumentException(s);    }  }  private Action action;  private String version;  private URI uri;  public Action action() { return action; }  public String version() { return version; }  public URI uri() { return uri; }  private Request(Action a, String v, URI u) {    action = a;    version = v;    uri = u;  }  public String toString() {    return (action + " " + version + " " + uri);  }  private static Charset requestCharset = Charset.forName("GBK");  /* 判断ByteBuffer是否包含了HTTP请求的所有数据。   * HTTP请求以“\r\n\r\n”结尾。   */  public static boolean isComplete(ByteBuffer bb) {    ByteBuffer temp=bb.asReadOnlyBuffer();    temp.flip();    String data=requestCharset.decode(temp).toString();    if(data.indexOf("\r\n\r\n")!=-1){      return true;    }    return false;  }  /*   * 删除请求正文,本例子仅支持GET和HEAD请求方式,忽略HTTP请求中的正文部分   */  private static ByteBuffer deleteContent(ByteBuffer bb) {    ByteBuffer temp=bb.asReadOnlyBuffer();    String data=requestCharset.decode(temp).toString();    if(data.indexOf("\r\n\r\n")!=-1){        data=data.substring(0,data.indexOf("\r\n\r\n")+4);        return requestCharset.encode(data);    }    return bb;  }  /*   * 设定用于解析HTTP请求的字符串匹配模式。对于以下形式的HTTP请求:   *   *     GET /dir/file HTTP/1.1   *     Host: hostname   *   * 将被解析成:   *   *     group[1] = "GET"   *     group[2] = "/dir/file"   *     group[3] = "1.1"   *     group[4] = "hostname"   */  private static Pattern requestPattern      = Pattern.compile("\\A([A-Z]+) +([^ ]+) +HTTP/([0-9\\.]+)$"                        + ".*^Host: ([^ ]+)$.*\r\n\r\n\\z",                        Pattern.MULTILINE | Pattern.DOTALL);  /* 解析HTTP请求,创建相应的Request对象 */  public static Request parse(ByteBuffer bb) throws MalformedRequestException {    bb=deleteContent(bb); //删除请求正文    CharBuffer cb = requestCharset.decode(bb); //解码    Matcher m = requestPattern.matcher(cb);  //进行字符串匹配    //如果HTTP请求与指定的字符串模式不匹配,说明请求数据不正确    if (!m.matches())        throw new MalformedRequestException();    Action a;    try {  //获得请求方式        a = Action.parse(m.group(1));     } catch (IllegalArgumentException x) {        throw new MalformedRequestException();    }    URI u;    try { //获得URI        u = new URI("http://"                    + m.group(4)                    + m.group(2));    } catch (URISyntaxException x) {        throw new MalformedRequestException();    }    //创建一个Request对象,并将其返回    return new Request(a, m.group(3), u);  }}
9.RequestHanlder..java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;public class RequestHandler implements Handler {  private ChannelIO channelIO;  private ByteBuffer requestByteBuffer = null;  //存放HTTP请求的缓冲区  private boolean requestReceived = false;  //是否已经接收到了所有的HTTP请求  private Request request = null;  //表示HTTP请求  private Response response = null;  //表示HTTP响应  RequestHandler(ChannelIO channelIO) {    this.channelIO = channelIO;  }  /*    * 接收HTTP请求,如果已经接收到了所有的HTTP请求数据,就返回true,否则返回false   */  private boolean receive(SelectionKey sk) throws IOException {    ByteBuffer tmp = null;    if (requestReceived)return true;  //如果已经接收到所有HTTP请求数据,返回true        //如果已经读到通道的末尾,或者已经读到HTTP请求数据的末尾标志“\r\n”,就返回true    if ((channelIO.read() < 0) || Request.isComplete(channelIO.getReadBuf())) {      requestByteBuffer = channelIO.getReadBuf();      return (requestReceived = true);    }    return false;  }  /*   * 通过Request类的parse()方法,解析requestByteBuffer中的HTTP请求数据,构造相应的Request对象    */  private boolean parse() throws IOException {    try {      request = Request.parse(requestByteBuffer);      return true;    } catch (MalformedRequestException x) {        //如果HTTP请求的格式不正确,就发送错误信息      response = new Response(Response.Code.BAD_REQUEST,                          new StringContent(x));    }    return false;  }  /*   * 创建HTTP响应    */  private void build() throws IOException {    Request.Action action = request.action();    //仅仅支持GET和HEAD请求方式    if ((action != Request.Action.GET) &&            (action != Request.Action.HEAD)){       response = new Response(Response.Code.METHOD_NOT_ALLOWED,                          new StringContent("Method Not Allowed"));    }else{       response = new Response(Response.Code.OK,                      new FileContent(request.uri()), action);    }  }    /*  接收HTTP请求,发送HTTP响应 */  public void handle(SelectionKey sk) throws IOException {    try {        if (request == null) { //如果还没有接收到HTTP请求的所有数据            //接收HTTP请求                  if (!receive(sk))return;            requestByteBuffer.flip();                 //如果成功解析了HTTP请求,就创建一个Response对象            if (parse())build();                 try {                response.prepare();  //准备HTTP响应的内容            } catch (IOException x) {                response.release();                  response = new Response(Response.Code.NOT_FOUND,                                  new StringContent(x));                response.prepare();            }            if (send()) {                 //如果HTTP响应没有发送完毕,则需要注册写就绪事件,               //以便在写就绪事件发生时继续发送数据               sk.interestOps(SelectionKey.OP_WRITE);            } else {               //如果HTTP响应发送完毕,就断开底层的连接,并且释放Response占用的资源               channelIO.close();               response.release();            }        } else {  //如果已经接收到HTTP请求的所有数据            if (!send()) {  //如果HTTP响应发送完毕              channelIO.close();              response.release();            }        }    } catch (IOException x) {        x.printStackTrace();        channelIO.close();        if (response !=  null) {            response.release();        }    }  }  /* 发送HTTP响应,如果全部发送完毕,就返回false,否则返回true */    private boolean send() throws IOException {    return response.send(channelIO);  }}
10.Response.java

package Test;import java.io.*;import java.nio.*;import java.nio.charset.*;public class Response implements Sendable {  static class Code {  //枚举类,表示状态代码    private int number;    private String reason;    private Code(int i, String r) { number = i; reason = r; }    public String toString() { return number + " " + reason; }    static Code OK = new Code(200, "OK");    static Code BAD_REQUEST = new Code(400, "Bad Request");    static Code NOT_FOUND = new Code(404, "Not Found");    static Code METHOD_NOT_ALLOWED = new Code(405, "Method Not Allowed");  }  private Code code;  //状态代码  private Content content;  //响应正文  private boolean headersOnly;  //表示HTTP响应中是否仅包含响应头  private ByteBuffer headerBuffer = null;  //响应头  public Response(Code rc, Content c) {    this(rc, c, null);  }  public Response(Code rc, Content c, Request.Action head) {    code = rc;    content = c;    headersOnly = (head == Request.Action.HEAD);  }  private static String CRLF = "\r\n";  private static Charset responseCharset = Charset.forName("GBK");  /* 创建响应头的内容,把它存放到一个ByteBuffer中 */  private ByteBuffer headers() {    CharBuffer cb = CharBuffer.allocate(1024);    for (;;) {        try {            cb.put("HTTP/1.1 ").put(code.toString()).put(CRLF);            cb.put("Server: nio/1.1").put(CRLF);            cb.put("Content-type: ").put(content.type()).put(CRLF);            cb.put("Content-length: ")                .put(Long.toString(content.length())).put(CRLF);            cb.put(CRLF);            break;        } catch (BufferOverflowException x) {            assert(cb.capacity() < (1 << 16));            cb = CharBuffer.allocate(cb.capacity() * 2);            continue;        }    }    cb.flip();    return responseCharset.encode(cb);  //编码  }  /* 准备HTTP响应中的正文以及响应头的内容 */  public void prepare() throws IOException {    content.prepare();    headerBuffer= headers();  }  /* 发送HTTP响应,如果全部发送完毕,返回false,否则返回true */  public boolean send(ChannelIO cio) throws IOException {    if (headerBuffer == null)        throw new IllegalStateException();    //发送响应头    if (headerBuffer.hasRemaining()) {        if (cio.write(headerBuffer) <= 0)            return true;    }    //发送响应正文    if (!headersOnly) {        if (content.send(cio))            return true;    }    return false;  }  /* 释放响应正文占用的资源 */  public void release() throws IOException {    content.release();  }}
11.Sendable.java

package Test;import java.io.*;/* *表示服务器可以发送给客户端的东西 */public interface Sendable {  // 准备发送的内容  public void prepare() throws IOException;  // 利用通道发送部分内容,如果所有内容发送完毕,就返回false  // 如果还有内容未发送,就返回true  // 如果内容还没有准备好,就抛出IllegalStateException  public boolean send(ChannelIO cio) throws IOException;  //当服务器发送内容完毕,就调用此方法,释放内容占用的资源  public void release() throws IOException;}
12.SimpleHttpServer.java

package Test;import java.io.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;import java.net.*;import java.util.*;import java.util.concurrent.*;public class SimpleHttpServer {  private int port=80;  private ServerSocketChannel serverSocketChannel = null;  private ExecutorService executorService;  private static final int POOL_MULTIPLE = 4;  public SimpleHttpServer() throws IOException {    executorService= Executors.newFixedThreadPool(	    Runtime.getRuntime().availableProcessors() * POOL_MULTIPLE);    serverSocketChannel= ServerSocketChannel.open();    serverSocketChannel.socket().setReuseAddress(true);    serverSocketChannel.socket().bind(new InetSocketAddress(port));    System.out.println("服务器启动");  }  public void service() {    while (true) {      SocketChannel socketChannel=null;      try {        socketChannel = serverSocketChannel.accept();        executorService.execute(new Handler(socketChannel));      }catch (IOException e) {         e.printStackTrace();      }    }  }  public static void main(String args[])throws IOException {    new SimpleHttpServer().service();  }  class Handler implements Runnable{  private SocketChannel socketChannel;  public Handler(SocketChannel socketChannel){    this.socketChannel=socketChannel;  }  public void run(){    handle(socketChannel);  }  public void handle(SocketChannel socketChannel){    try {        Socket socket=socketChannel.socket();        System.out.println("接收到客户连接,来自: " +        socket.getInetAddress() + ":" +socket.getPort());         ByteBuffer buffer=ByteBuffer.allocate(1024);         socketChannel.read(buffer);         buffer.flip();         String request=decode(buffer);         System.out.print(request);  //打印HTTP请求         //输出HTTP响应结果         StringBuffer sb=new StringBuffer("HTTP/1.1 200 OK\r\n");         sb.append("Content-Type:text/html\r\n\r\n");         socketChannel.write(encode(sb.toString()));//输出响应头         FileInputStream in;         //获得HTTP请求的第一行         String firstLineOfRequest=request.substring(0,request.indexOf("\r\n"));         if(firstLineOfRequest.indexOf("login.htm")!=-1)            in=new FileInputStream("root/login.htm");         else            in=new FileInputStream("root/hello.htm");         FileChannel fileChannel=in.getChannel();         fileChannel.transferTo(0,fileChannel.size(),socketChannel);         fileChannel.close();      }catch (Exception e) {         e.printStackTrace();      }finally {         try{           if(socketChannel!=null)socketChannel.close();         }catch (IOException e) {e.printStackTrace();}      }  }  private Charset charset=Charset.forName("GBK");  public String decode(ByteBuffer buffer){  //解码    CharBuffer charBuffer= charset.decode(buffer);    return charBuffer.toString();  }  public ByteBuffer encode(String str){  //编码    return charset.encode(str);  } }}
13.StringContent.java

package Test;import java.io.*;import java.nio.*;import java.nio.charset.*;/* 字符串形式的内容 */public class StringContent implements Content {    private static Charset charset = Charset.forName("GBK");    private String type;		// MIME type    private String content;    public StringContent(CharSequence c, String t) {	content = c.toString();	if (!content.endsWith("\n"))	    content += "\n";	type = t + "; charset=GBK";    }    public StringContent(CharSequence c) {	this(c, "text/plain");    }    public StringContent(Exception x) {	StringWriter sw = new StringWriter();	x.printStackTrace(new PrintWriter(sw));	type = "text/plain; charset=GBK";	content = sw.toString();    }    public String type() {	return type;    }    private ByteBuffer bb = null;    private void encode() {	if (bb == null)	    bb = charset.encode(CharBuffer.wrap(content));    }    public long length() {	encode();	return bb.remaining();    }    public void prepare() {	encode();	bb.rewind();    }    public boolean send(ChannelIO cio) throws IOException {	if (bb == null)	    throw new IllegalStateException();	cio.write(bb);	return bb.hasRemaining();    }    public void release() throws IOException {}}

你可能感兴趣的文章
SQL索引一步到位
查看>>
SQL行转列汇总
查看>>
sqlserver、db2、oracle存储过程动态sql语句示例
查看>>
DB2和oracle以及MS的SQL Server比
查看>>
jsf中xhtml文件访问
查看>>
数据库中CHAR,VARCHAR,TEXT等字段的区别
查看>>
greenplum 与 hbase的区别
查看>>
String、StringBuffer与StringBuilder之间区别
查看>>
Elasticsearch、MongoDB和Hadoop比较
查看>>
Elasticsearch与hadoop比较
查看>>
外地人一年内直接落户上海
查看>>
测试用例设计--因果图
查看>>
Kafka 对比 ActiveMQ
查看>>
架构以及我理解中架构的本质
查看>>
如何将Lucene索引写入Hadoop1.x的HDFS系统
查看>>
标量数据类型
查看>>
Lucene 或者 solr 有什么不一样
查看>>
MapReduce来构建索引
查看>>
Lucene和Solr从数据库加载词库分析
查看>>
CSS 让div内的span在一行显示
查看>>