一个简单的HTTP请求与应答基于socket
2017-08-03 18:47
246 查看
tomcat是一个web容器,网络请求基于HTTP,HTTP底层基于socket抽象层,直接上图(盗的图)
我就简单实现了一个socket来模拟HTTP请求与应答
代码的逻辑非常简单,先是获得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小图标了》
我就简单实现了一个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小图标了》
相关文章推荐
- 基于Socket编程实现一个简单的Web服务器
- 网络编程与多线程的应用--基于socket udp编写一个简单聊天程序
- Java实现一个简单的RPC框架(五) 基于Socket的传输层实现
- 一个基于Socket的http请求监听程序实现
- 基于Qt5.9Creator的一个简单socket通信实例(C++语言,win7 64系统)
- 一个基于Socket的http请求监听程序实现
- 【socket编程】 一个简单的基于TCP连接的客户端、服务端用例
- java基于Socket做一个简单下载器
- 基于tcp的c/s模型的一个简单的socket实现
- 一个简单的基于socket的通讯处理程序
- 【socket编程】一个简单的基于TCP的客户/服务端例子(vs2008)
- 【socket编程】一个简单的基于UDP的客户/服务端例子(vs2008)
- 一个基于python简单的装饰器实例
- 一个简单的socket例子
- 一个简单的linux下原生socket的tcp程序及其修改
- 用C#设计一个基于UDP协议的简单网络聊天器
- 一个简单的基于用户的mahout推荐程序
- 一个最简单的基于Android SearchView的搜索框
- 一个简单的基于UDP字符界面的聊天应用程序(C/C++)
- 一个简单实用的“数据库访问层”!(基于C#语言)