指定字符集和编码
<properties>
<maven.compiler.target>1.8maven.compiler.target>
<maven.compiler.source>1.8maven.compiler.source>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8maven.compiler.encoding>
properties>
服务端代码如下
/**
* WebServer web容器
* 用于实现Tomcat基本功能
*/
public class WebServerApplication {
private ServerSocket serverSocket;
public WebServerApplication() {
try {
System.out.println("启动服务端...");
serverSocket=new ServerSocket(8088);
System.out.println("启动完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
System.out.println("等到客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("一个客户端已连接");
ClientHandler handler=new ClientHandler(socket);
Thread t=new Thread(handler);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
WebServerApplication server=new WebServerApplication();
server.start();
}
}
创建Module子项目


然后V1项目的pom.xml变成如下

需求分析
HTTP协议要求浏览器连接服务端后应当发送一个请求,因此版本实现读取请求,并输出到控制台来了解请求的格式和内容
实现:
由于服务端可以同时接收多客户端的连接,因此与聊天室相同,主线程仅负责客户端的连接,一旦一个客户端
连接后则启动一个线程来处理。
1:在com.webserver.core下新建类:ClientHandler(实现Runnable接口),作为线程任务,
工作是负责与连接的客户端进行HTTP交互
2.WebServerApplication主线程节后连接后启动ClientHandler这个任务处理客户端交互
3.在ClientHandler中读取客户端发送过来的内容(请求内容)big打桩输出
处理客户端的请求
/**
* 与客户端完成一次HTTP的交互
*/
package com.webserver.core;
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
InputStream is = socket.getInputStream();
// http://localhost:8088/index.html
int d;
while ((d=is.read())!=-1){//这样可以不止读取文本信息
char c=(char)d;
System.out.print(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
访问服务端http://localhost:8088/
打印信息如下


package com.webserver.core;
/**
* 与客户端完成一次HTTP的交互
* 按照HTTP协议请求,与客户端完成一次交互流程为一问一答
* 因此,这里分为三步完成该工作:
* 1:解析请求 目的:将浏览器发送的请求内容读取并整理
* 2:处理请求 目的:根据浏览器的请求进行对应的处理工作
* 3:发送响应 目的:将服务端的处理结果回馈给浏览器
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
InputStream is = socket.getInputStream();
// http://localhost:8088/index.html
int d;
StringBuilder builder=new StringBuilder();
char cur=' ';
char pre=' ';
while ((d=is.read())!=-1){//这样可以不止读取文本信息
cur=(char)d;
if(cur==10&&pre==13){
break;
}
builder.append(cur);
pre=cur;
}
String line=builder.toString();
System.out.println(line.trim());
//请求行相关信息
String method;
String uri;//抽象路径
String protocol;//协议版本
String[] data = line.split("\\s");
method=data[0];
uri=data[1];
protocol=data[2];
System.out.println("method:"+method);
System.out.println("uri:"+uri);
System.out.println("protocol:"+protocol);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
String line=readLine();
System.out.println("请求行:"+line);
//请求相关信息
String method;//请求方式
String uri;//抽象路径
String protocol;//协议版本
String[] data = line.split("\\s");
method=data[0];
uri=data[1];
protocol=data[2];
System.out.println("method:"+method);
System.out.println("uri:"+uri);
System.out.println("protocol:"+protocol);
} catch (IOException e) {
e.printStackTrace();
}
}
//定义一次读取一行的方法
private String readLine() throws IOException {
InputStream is = socket.getInputStream();
int d;
StringBuilder builder=new StringBuilder();
char cur=' ';
char pre=' ';
while ((d=is.read())!=-1){//这样可以不止读取文本信息
cur=(char)d;
if(cur==10&&pre==13){
break;
}
builder.append(cur);
pre=cur;
}
return builder.toString().trim();
}
}
获取所有消息头信息

public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
String line=readLine();
System.out.println("请求行:"+line);
//请求相关信息
String method;//请求方式
String uri;//抽象路径
String protocol;//协议版本
String[] data = line.split("\\s");
method=data[0];
uri=data[1];
protocol=data[2];
System.out.println("method:"+method);
System.out.println("uri:"+uri);
System.out.println("protocol:"+protocol);
//获取消息头
while (true){
line=readLine();
if(line.isEmpty()){//如果单独读取回车+换行,readLine方法会返回空串
break;
}
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//定义一次读取一行的方法
private String readLine() throws IOException {
InputStream is = socket.getInputStream();
int d;
StringBuilder builder=new StringBuilder();
char cur=' ';
char pre=' ';
while ((d=is.read())!=-1){//这样可以不止读取文本信息
cur=(char)d;
if(cur==10&&pre==13){
break;
}
builder.append(cur);
pre=cur;
}
return builder.toString().trim();
}
}
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
String line=readLine();
System.out.println("请求行:"+line);
//请求相关信息
String method;//请求方式
String uri;//抽象路径
String protocol;//协议版本
String[] data = line.split("\\s");
method=data[0];
uri=data[1];
protocol=data[2];
System.out.println("method:"+method);
System.out.println("uri:"+uri);
System.out.println("protocol:"+protocol);
Map<String,String> headers=new HashMap<>();
//获取消息头
while (true){
line=readLine();
if(line.isEmpty()){//如果单独读取回车+换行,readLine方法会返回空串
break;
}
System.out.println("原消息头:"+line);
String[] arrayStr = line.split(":");
headers.put(arrayStr[0],arrayStr[1]);
}
System.out.println("-----------------------");
headers.forEach((k,v)-> System.out.println("集合中的消息头:"+k+":"+v));
} catch (IOException e) {
e.printStackTrace();
}
}
//定义一次读取一行的方法
private String readLine() throws IOException {
InputStream is = socket.getInputStream();
int d;
StringBuilder builder=new StringBuilder();
char cur=' ';
char pre=' ';
while ((d=is.read())!=-1){//这样可以不止读取文本信息
cur=(char)d;
if(cur==10&&pre==13){
break;
}
builder.append(cur);
pre=cur;
}
return builder.toString().trim();
}
}