写http服务器就得知道http协议,这个协议是基于 tcp/ip的,所以我们可以用 ServerSocket 写服务端
客户端就是浏览器,浏览器其实也是通过socket 连接客户端的,一般来说浏览器请求服务器资源的时候,都会带上 请求头信息
就像这样:
请求头里面包含了,请求地址,请求方法,客户端语言,浏览器信息,等等,服务端使用 socket.getInputStream 可以读取到
HTTP协议,所谓协议,就是按照一定的规则,进行数据交换,我们得按照 http协议的规定进行返回数据,浏览器才能正确解析我们返回的数据。
这里我们得注意下,空格 和换行,这个在 返回得头文件里面是必须得
现在来看看代码吧,极简版的,也没管封装啥的,就这样吧,有兴趣得同学可以自己研究下
服务端应该是不停运转得,请求也是并发执行得,所以得使用 多线程和 死循环
调用代码:
ServerSocket server = new ServerSocket(80);
long count = 0;
while (true) {
Socket socket = server.accept(); // 获取客户端连接
System.out.println("第["+ (++count) +"]个客户端!ip为:" + socket.getInetAddress().getHostAddress() + " 访问时间: " + new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date()) );
new Thread( new Server(socket) ).start();
}
Server类:
/**
* server
*
* @author snow
*
*/
public class Server implements Runnable {
// 两个常量
private static final String CRLF = "\r\n";
private static final String BLANK = " ";
private Socket server;
private String path;
public Server(Socket server) {
this.server = server;
System.out.println( "客户端:" + this.server.getInetAddress().getHostName() +" 的请求头文件为:" );
System.out.println( getData() );
}
private String getData() {
try {
BufferedInputStream bis = new BufferedInputStream( this.server.getInputStream() );
byte [] data = new byte[2048];
int len = bis.read(data);
String msg = new String(data,0,len);
int start = msg.indexOf("/");
int end = msg.indexOf("HTTP");
this.path = msg.substring((start+1), end).trim();
return msg;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private void sendData() {
try {
BufferedOutputStream bos = new BufferedOutputStream(this.server.getOutputStream());
String suffix = path.substring(path.lastIndexOf(".")+1);
File file = new File(path);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
StringBuffer sb = new StringBuffer();
// http 协议版本,状态码,描述
sb.append("HTTP/1.1").append(BLANK).append(520).append(BLANK).append("love").append(CRLF);
// 响应头
sb.append("Server:Pkusoft Server/12.19.06.14").append(CRLF).append("Date:").append(new Date()).append(CRLF)
;
if( "jpg".equals(suffix)) {
sb.append("Content-type:image/jpg").append(CRLF);
}else if("png".equals(suffix)) {
sb.append("Content-type:image/png").append(CRLF);
}else if("gif".equals(suffix)) {
sb.append("Content-type:image/gif").append(CRLF);
}else if("html".equals(suffix)) {
sb.append("Content-type:text/html").append(CRLF);
}else if("css".equals(suffix)) {
sb.append("Content-type:text/css").append(CRLF);
}else if("js".equals(suffix)) {
sb.append("Content-type:application/x-javascript").append(CRLF);
}else {
sb.append("Content-type:application/octet-stream").append(CRLF);
}
sb.append("Connection:keep-alive").append(CRLF);
// 正文长度:内容
sb.append("Content-Length:").append(file.length()).append(CRLF).append(CRLF);
bos.write(sb.toString().getBytes());
byte [] flush = new byte[1024*1024];
int len = bis.read(flush);
// while( (len=bis.read(flush)) != -1 ){
bos.write(flush, 0, len);
System.out.println( "读取成功!==>" + path );
// }
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
sendData();
}
}
运行效果:
打印请求头信息:
页面效果: