用java socket实现了一个简单的http服务器, 可以处理GET, POST,以及带一个附件的multipart类型的POST。虽然中途遇到了很多问题, 不过通过在论坛和几个高手交流了一下,问题都解决了。如果你觉得程序有些地方看不明白,可以参看这个帖子:http://topic.csdn.net/u/20090625/22/59a5bfc8-a6b6-445d-9829-ea6d462a4fe6.html .
虽然解析http头不是很规范,本来应该用原始的字节流, 我采用了一个折衷的方案,用DataInputStream.
本代码的实用性==0,但是可以帮助很好地了解http协议,然后其他的应用层协议大都如此。
如果你从来都没有了解过http协议,建议先搜索阅读一下,或者你还可以用下面的代码来简单的看一看到底浏览器和服务器之间都相互发送了什么数据。
MyHttpClient.java: 模拟浏览器的行为, 向服务器发送get/post请求,然后打印出服务器返回的消息。这样就可以查看当一个请求到来之后, 服务器到底都给浏览器发送了哪些消息。
package socket; import java.io.*; import java.net.*; public class MyHttpClient { public static void main(String[] args) throws Exception{ InetAddress inet = InetAddress.getByName("www.baidu.com"); System.out.println(inet.getHostAddress()); Socket socket = new Socket(inet.getHostAddress(),80); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); PrintWriter writer = new PrintWriter(out); writer.println("GET /home.html HTTP/1.1");//home.html是关于百度的页面 writer.println("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*"); writer.println("Accept-Language: en-us,zh-cn;q=0.5"); writer.println("Accept-Encoding: gzip, deflate"); writer.println("Host: www.baidu.com"); writer.println("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); writer.println("Connection: Keep-Alive"); writer.println(); writer.flush(); String line = reader.readLine(); while(line!=null){ System.out.println(line); line = reader.readLine(); } reader.close(); writer.close(); } }
MyServer.java: 模拟server端接收浏览器的请求,然后把整个请求的报文打印出来。程序运行之后直接用浏览器测试。
package socket; import java.io.*; import java.net.*; public class MyServer { public static void main(String[] args) throws IOException{ ServerSocket svrSocket = new ServerSocket(8080); while(true){ Socket socket = svrSocket.accept(); //足够大的一个缓冲区 byte[] buf = new byte[1024*1024]; InputStream in = socket.getInputStream(); int byteRead = in.read(buf, 0, 1024*1024); String dataString = new String(buf, 0, byteRead); System.out.println(dataString); in.close(); socket.close(); } } }
主程序MyHttpServer.
package socket; import java.io.*; import java.net.*; /** * MyHttpServer 实现一个简单的HTTP服务器端,可以获取用户提交的内容 * 并给用户一个response * 因为时间的关系,对http头的处理显得不规范 * 对于上传附件,暂时只能解析只上传一个附件而且附件位置在第一个的情况 * 转载请注明来自http://blog.csdn.net/sunxing007 * **/ 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