socket编程入门,需要实现的目标:
1,不用框架利用socket编程实现一个http服务框架
2,实现基本的Request/Response封装
3, 思考io和线程模型的关系
首先我们了解一下网络插槽socket,当客户端和服务端在进行交互的时候,会分别产生一个socket,然后这两个socket进行交互,比如客户端想发送信息的时候,先发给socket,接收信息会从socket里读, 这里可以看出socket类似于文件,其实很多操作系统把socket封装成了文件。
服务端线程模型:
当我们的操作系统接收到客户端发出的web请求的时候,它会先把这个请求(比如tcp连接的请求)扔到Pending Queue里面,如果满了操作系统会拒绝请求,否则这个请求不断的积累到队列里,直到某一个线程进行accept这个系统调用,这个系统调用会从队列里拿出一个请求,接收之后会在操作系统内核中形成socket文件,这个socket文件对应着资源的FD(可以理解为操作文件资源的东西,其实就是socket),因为具体的文件在内核中,用文件的是具体的线程,这个线程不断循环,不断接收请求生成对应的FD,然后由工作线程读取socket的内容,分析其中的内容,处理完后写入socket文件,操作系统监听到文件被写入后,会把结果送到网卡,通过网络传给请求方。
第一个httpserver:
package com.hai;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class RawHttpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8001);
// Main Thread
while (true){
// Blocking---
// Thread--->sleep
Socket socket = serverSocket.accept();
// socket来操控内核中的文件
System.out.println("A socket created");
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));
StringBuilder stringBuilder = new StringBuilder();
String line="";
// Readline -> line end 'n'
while (!(line=bufferedReader.readLine()).isEmpty()){
stringBuilder.append(line);
}
String request = stringBuilder.toString();
System.out.println(request);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("HTTP/1.1 200 oknnHello World!n");
bufferedWriter.flush();
socket.close();
}
}
}
抽象成类:
public class Step1Server {
ServerSocket serverSocket;
Function handler;
public Step1Server(Function handler){
this.handler=handler;
}
// pending Queue
public void listen(int port) throws IOException {
serverSocket = new ServerSocket(port);
while (true){
this.accept();
}
}
void accept() throws IOException {
// Blocking---
// Thread--->sleep
try {
Socket socket = serverSocket.accept();
// socket来操控内核中的文件
System.out.println("A socket created");
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));
StringBuilder stringBuilder = new StringBuilder();
String line="";
// Readline -> line end 'n'
while (true){
line=bufferedReader.readLine();
if(line==null||line.isEmpty()){
break;
}
stringBuilder.append(line+'n');
}
String request = stringBuilder.toString();
System.out.println(request);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String response = this.handler.apply(request);
bufferedWriter.write(response);
bufferedWriter.flush();
socket.close();
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
Step1Server server = new Step1Server(req -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "HTTP/1.1 200 oknnHello World1!n";
});
server.listen(8001);
}
http服务的多线程优化:
public class Step2Server {
ServerSocket serverSocket;
Function handler;
public Step2Server(Function handler){
this.handler=handler;
}
// pending Queue
public void listen(int port) throws IOException {
serverSocket = new ServerSocket(port);
while (true){
this.accept();
}
}
void accept() throws IOException {
// Blocking..
Socket socket = serverSocket.accept();
new Thread(()->{
try {
this.hander(socket);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
void hander(Socket socket) throws IOException {
// Blocking---
// Thread--->sleep
try {
// Socket socket = serverSocket.accept();
// socket来操控内核中的文件
System.out.println("A socket created");
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));
StringBuilder stringBuilder = new StringBuilder();
String line="";
// Readline -> line end 'n'
while (true){
line=bufferedReader.readLine();
if(line==null||line.isEmpty()){
break;
}
stringBuilder.append(line+'n');
}
String request = stringBuilder.toString();
System.out.println(request);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String response = this.handler.apply(request);
bufferedWriter.write(response);
bufferedWriter.flush();
socket.close();
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
Step2Server server = new Step2Server(req -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "HTTP/1.1 200 oknnHello World1!n";
});
server.listen(8001);
}
}



