您的位置:首页 > 理论基础 > 计算机网络

一个简单的HTTP请求与应答基于socket

2017-08-03 18:47 246 查看
  tomcat是一个web容器,网络请求基于HTTP,HTTP底层基于socket抽象层,直接上图(盗的图)



  我就简单实现了一个socket来模拟HTTP请求与应答

package Socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* Created by Jackie on 2017/8/2.
*
*/
public class HttpSocket {

private static final String OUTPUT = "<html><head><title>Example</title></head><body><p>Worked!!!</p></body></html>";
private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: ";
private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

public void start() {
try {
ServerSocket serverSocket = new ServerSocket(9002);
boolean isStop = false;

while (!isStop) {
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = bufferedReader.readLine())!=null){
System.out.println(line);
if (line.isEmpty())
break;
}
sendResponse(socket);
socket.close();

}
} catch (Exception e) {
e.printStackTrace();
}
}

public void sendResponse(Socket socket) throws IOException {
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write(OUTPUT_HEADERS + OUTPUT.length() + OUTPUT_END_OF_HEADERS + OUTPUT);
bw.flush();
bw.close();
}

public static void main(String[] args){
new HttpSocket().start();
}
}


  代码的逻辑非常简单,先是获得HTTP请求,打印其HTTP的request部分,然后获得输出流,按照HTTP中response的响应格式,输出一个简单的html。最终的效果就是,在浏览器中输入http://localhost:9002/ 就会返回一个简单的html页面,效果如下图:

  


  其中有一个好玩的现象,当我在浏览器敲入localhost:9002的时候,后台程序打印出来发现浏览器发送了两次HTTP请求:

GET / HTTP/1.1

Host: localhost:9002

Connection: keep-alive

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4

Cookie: Idea-d1657464=19a93302-2aa0-4496-a546-c42fd7726ea0

GET /favicon.ico HTTP/1.1

Host: localhost:9002

Connection: keep-alive

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36

Accept: image/webp,image/apng,image/*,*/*;q=0.8

Referer: http://localhost:9002/
Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4

Cookie: Idea-d1657464=19a93302-2aa0-4496-a546-c42fd7726ea0

  其中第一次请求使我们比较熟悉的,但是第二次请求我从来没注意到过,但是看了下请求的格式,好像大概的能明白请求的意图从第一行就可以看出来请求的是一个icon,我们每次打开一个网页的时候,你有没有注意到每个网页标签页左上角都会有一个icon小图标。既然遇到了这个有趣的地方,那么要去实现这个功能,程序改的也比较简单,当第二次HTTP请求的时候,我们返回一个带有图片文件的Response。程序如下:

package Socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* Created by Jackie on 2017/8/2.
*
*/
public class HttpSocket {

private static final String OUTPUT = "<html><head><title>Example</title></head><body><p>Worked!!!</p></body></html>";

private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: ";

private static final String OUTPUT_HEADERS_IOCN = "HTTP/1.1 200 OK\r\n" +
"Content-Type: image/*\r\n" +
"Content-Length: ";

private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

private static final String Icon_Location = "/Users/macbookpro/Desktop/resizeApi.png";

public void start() {
try {
ServerSocket serverSocket = new ServerSocket(9002);
boolean isStop = false;
boolean isIconRequest = false;
while (!isStop) {
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = bufferedReader.readLine())!=null){
System.out.println(line);
if(line.contains("GET /favicon.ico")){
sendIcon(Icon_Location , socket);
isIconRequest = true;
}
if (line.isEmpty())
break;
}

if (!isIconRequest)
sendResponse(socket);

socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}

public void sendResponse(Socket socket) throws IOException {
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write(OUTPUT_HEADERS + OUTPUT.length() + OUTPUT_END_OF_HEADERS + OUTPUT);
bw.flush();
bw.close();
}

public void sendIcon(String iconLocation , Socket socket) throws IOException {
File file = new File(iconLocation);
if (!file.exists())
throw new FileNotFoundException();

BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream fileOut = new BufferedOutputStream(socket.getOutputStream());

fileOut.write(OUTPUT_HEADERS.getBytes());
fileOut.write(String.valueOf(file.length()).getBytes());
fileOut.write(OUTPUT_END_OF_HEADERS.getBytes());

byte[] buf = new byte[1024];
int size = 0;
while ((size = fileIn.read(buf))>0){
fileOut.write(buf , 0 , size);
}

fileOut.flush();
fileOut.close();
fileIn.close();
}

public static void main(String[] args) throws IOException {
new HttpSocket().start();
}
}  发送图片的IO流我选择了字节流,因为在以前我尝试用字符去复制二进制图片文件时,复制完成后打不开了,提示我格式有错误,然后我选择了字节流就解决了这个问题。最终的返回页面如图:



  在标签的左上角就有了一个github小图标了》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: