网络编程--05 HTTP服务器
Posted Anrys
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程--05 HTTP服务器相关的知识,希望对你有一定的参考价值。
网络编程--05 HTTP服务器
6.HTTP服务器
6.1需求
编写服务器端代码,实现可以解析浏览器的请求,给浏览器响应数据
6.2环境搭建
实现步骤:
1.编写HttpServer类,实现可以接收浏览器发出的请求
2.其中获取连接的代码可以单独抽取到一个类中
代码:
// 服务端代码
public class HttpServer {
public static void main(String[] args) throws IOException {
//1.打开服务端通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.让这个通道绑定一个端口
serverSocketChannel.bind(new InetSocketAddress(10000));
//3.设置通道为非阻塞
serverSocketChannel.configureBlocking(false);
//4.打开一个选择器
Selector selector = Selector.open();
//5.绑定选择器和服务端通道
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
while(true){
//6.选择器会监视通道的状态.
int count = selector.select();
if(count != 0){
//7.会遍历所有的服务端通道.看谁准备好了,谁准备好了,就让谁去连接.
//获取所有服务端通道的令牌,并将它们都放到一个集合中,将集合返回.
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
//selectionKey 依次表示每一个服务端通道的令牌
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()){
//获取连接
AcceptHandler acceptHandler = new AcceptHandler();
acceptHandler.connSocketChannel(selectionKey);
}else if(selectionKey.isReadable()){
}
//任务处理完毕以后,将SelectionKey从集合中移除
iterator.remove();
}
}
}
}
}
// 将获取连接的代码抽取到这个类中
public class AcceptHandler {
public SocketChannel connSocketChannel(SelectionKey selectionKey){
try {
//获取到已经就绪的服务端通道
ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = ssc.accept();
//设置为非阻塞状态
socketChannel.configureBlocking(false);
//把socketChannel注册到选择器上
socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ);
return socketChannel;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
6.3获取请求信息并解析
/**
* 用来封装请求数据的类
*/
public class HttpRequest {
private String method; //请求方式
private String requestURI; //请求的uri
private String version; //http的协议版本
private HashMap<String,String> hm = new HashMap<>();//所有的请求头
//parse --- 获取请求数据 并解析
public void parse(SelectionKey selectionKey){
try {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
StringBuilder sb = new StringBuilder();
//创建一个缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int len;
//循环读取
while((len = socketChannel.read(byteBuffer)) > 0){
byteBuffer.flip();
sb.append(new String(byteBuffer.array(),0,len));
//System.out.println(new String(byteBuffer.array(),0,len));
byteBuffer.clear();
}
//System.out.println(sb);
parseHttpRequest(sb);
} catch (IOException e) {
e.printStackTrace();
}
}
//解析http请求协议中的数据
private void parseHttpRequest(StringBuilder sb) {
//1.需要把StringBuilder先变成一个字符串
String httpRequestStr = sb.toString();
//2.获取每一行数据
String[] split = httpRequestStr.split("\\r\\n");
//3.获取请求行
String httpRequestLine = split[0];//GET / HTTP/1.1
//4.按照空格进行切割,得到请求行中的三部分
String[] httpRequestInfo = httpRequestLine.split(" ");
this.method = httpRequestInfo[0];
this.requestURI = httpRequestInfo[1];
this.version = httpRequestInfo[2];
//5.操作每一个请求头
for (int i = 1; i < split.length; i++) {
String httpRequestHeaderInfo = split[i];//Host: 127.0.0.1:10000
String[] httpRequestHeaderInfoArr = httpRequestHeaderInfo.split(": ");
hm.put(httpRequestHeaderInfoArr[0],httpRequestHeaderInfoArr[1]);
}
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getRequestURI() {
return requestURI;
}
public void setRequestURI(String requestURI) {
this.requestURI = requestURI;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public HashMap<String, String> getHm() {
return hm;
}
public void setHm(HashMap<String, String> hm) {
this.hm = hm;
}
@Override
public String toString() {
return "HttpRequest{" +
"method='" + method + '\\'' +
", requestURI='" + requestURI + '\\'' +
", version='" + version + '\\'' +
", hm=" + hm +
'}';
}
}
6.4给浏览器响应数据
public class HttpResponse {
private String version; //协议版本
private String status; //响应状态码
private String desc; //状态码的描述信息
//响应头数据
private HashMap<String, String> hm = new HashMap<>();
private HttpRequest httpRequest; //我们后面要根据请求的数据,来进行一些判断
//给浏览器响应数据的方法
public void sendStaticResource(SelectionKey selectionKey) {
//1.给响应行赋值
this.version = "HTTP/1.1";
this.status = "200";
this.desc = "ok";
//2.将响应行拼接成一个单独的字符串 // HTTP/1.1 200 ok
String responseLine = this.version + " " + this.status + " " + this.desc + "\\r\\n";
//3.给响应头赋值
hm.put("Content-Type", "text/html;charset=UTF-8");
//4.将所有的响应头拼接成一个单独的字符串
StringBuilder sb = new StringBuilder();
Set<Map.Entry<String, String>> entries = hm.entrySet();
for (Map.Entry<String, String> entry : entries) {
sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\\r\\n");
}
//5.响应空行
String emptyLine = "\\r\\n";
//6.响应行,响应头,响应空行拼接成一个大字符串
String responseLineStr = responseLine + sb.toString() + emptyLine;
try {
//7.将上面三个写给浏览器
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer1 = ByteBuffer.wrap(responseLineStr.getBytes());
socketChannel.write(byteBuffer1);
//8.单独操作响应体
//因为在以后响应体不一定是一个字符串
//有可能是一个文件,所以单独操作
String s = "哎哟,妈呀,终于写完了.";
ByteBuffer byteBuffer2 = ByteBuffer.wrap(s.getBytes());
socketChannel.write(byteBuffer2);
//9.释放资源
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public HashMap<String, String> getHm() {
return hm;
}
public void setHm(HashMap<String, String> hm) {
this.hm = hm;
}
public HttpRequest getHttpRequest() {
return httpRequest;
}
public void setHttpRequest(HttpRequest httpRequest) {
this.httpRequest = httpRequest;
}
@Override
public String toString() {
return "HttpResponse{" +
"version='" + version + '\\'' +
", status='" + status + '\\'' +
", desc='" + desc + '\\'' +
", hm=" + hm +
", httpRequest=" + httpRequest +
'}';
}
}
6.5代码优化
/**
* 接收连接的任务处理类
*/
public class AcceptHandler {
public SocketChannel connSocketChannel(SelectionKey selectionKey){
try {
//获取到已经就绪的服务端通道
ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = ssc.accept();
//设置为非阻塞状态
socketChannel.configureBlocking(false);
//把socketChannel注册到选择器上
socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ);
return socketChannel;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 接收客户端请求的类
*/
public class HttpServer {
public static void main(String[] args) throws IOException {
//1.打开服务端通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.让这个通道绑定一个端口
serverSocketChannel.bind(new InetSocketAddress(10000));
//3.设置通道为非阻塞
serverSocketChannel.configureBlocking(false);
//4.打开一个选择器
Selector selector = Selector.open();
//5.绑定选择器和服务端通道
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
while(true){
//6.选择器会监视通道的状态.
int count = selector.select();
if(count != 0){
//7.会遍历所有的服务端通道.看谁准备好了,谁准备好了,就让谁去连接.
//获取所有服务端通道的令牌,并将它们都放到一个集合中,将集合返回.
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
//selectionKey 依次表示每一个服务端通道的令牌
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()){
//获取连接
AcceptHandler acceptHandler = new AcceptHandler();
acceptHandler.connSocketChannel(selectionKey);
}else if(selectionKey.isReadable()){
//读取数据
HttpRequest httpRequest = new HttpRequest();
httpRequest.parse(selectionKey);
System.out.println("http请求的数据为 ---->" + httpRequest);
if(httpRequest.getRequestURI() == null || "".equals(httpRequest.getRequestURI())){
selectionKey.channel();
continue;
}
System.out.println("...数据解析完毕,准备响应数据....");
//响应数据
HttpResponse httpResponse = new HttpResponse();
httpResponse.setHttpRequest(httpRequest);
httpResponse.sendStaticResource(selectionKey);
}
//任务处理完毕以后,将SelectionKey从集合中移除
iterator.remove();
}
}
}
}
}
/**
* 用来封装请求数据的类
*/
public class HttpRequest {
private String method; //请求方式
private String requestURI; //请求的uri
private String version; //http的协议版本
private HashMap<String,String> hm = new HashMap<>();//所有的请求头
//parse --- 获取请求数据 并解析
public void parse(SelectionKey selectionKey){
try {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
StringBuilder sb = new StringBuilder();
//创建一个缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int len;
//循环读取
while((len = socketChannel.read(byteBuffer)) > 0){
byteBuffer.flip();
sb.append(new String(byteBuffer.array(),0,len));
//System.out.println(new String(byteBuffer.array(),0,len));
byteBuffer.clear();
}
//System.out.println(sb);
parseHttpRequest(sb);
} catch (IOException e) {
以上是关于网络编程--05 HTTP服务器的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 报错 DioError [DioErrorType.DEFAULT]: Bad state: Insecure HTTP is not allowed by platform(代码片段