Http多线程版本
上一篇文章讲了HTTP是如何通过TCP协议传输到服务器上,以及服务器接收到的报文信息
请参考[HTTP与TCP的关系]
这篇文章主要讲述的多线程处理Http请求,关于多线程的好处我就不再叙述了。由于我们的
请求处理可能非常的耗时,导致服务器无法在规定的时间内出力请求,这样服务器的吞吐量比较低,
为了达到高吞吐量,往往在请求处理时使用多线程技术,不会影响接受请求线程,这样一来即使处理
请求的线程堵塞了也不会影响处理请求的线程,这个也是现在比较流行的Reactor模型。
首先来看看处理请求的线程代码:
/**
* 处理HTTP请求的一个类
* @author xin.qiliuhai 1045931706@qq.com
* @date 2018/4/29 19:15
*/
public class HttpHandler implements Runnable {
private Socket socket;
public HttpHandler(Socket socket){
this.socket=socket;
}
@Override
public void run() {
BufferedReader br=null;
BufferedWriter bw=null;
try{
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String s;
int contentLength = 0;
//4.输出请求体中的内容,并且将Content-Length的值赋值给contentLength,确定post请求体的大小
while ((s = br.readLine()) != null && !s.isEmpty()) {
System.out.println(s);
if (s.indexOf("Content-Length") != -1) {
contentLength = Integer.parseInt(s.substring(s.indexOf("Content-Length") + 16));
}
}
//5.如果有请求体,通过read方法读取请求体中的内容
if (contentLength != 0) {
char[] buf = null;
if (contentLength != 0) {
buf = new char[contentLength];
br.read(buf, 0, contentLength);
System.out.println("The data user posted: " + new String(buf));
}
}
//6 设置响应体内容
bw.write("HTTP/1.1 200 OK\n");
bw.write("Content-Type: text/html; charset=UTF-8\n\n");
bw.write("<html>\n" +
"<head>\n" +
" <title>first page</title>\n" +
"</head>\n" +
"<body>\n" +
" <h1>Hello World!" + "</h1>\n" +
"</body>\n" +
"</html>\n");
//7.冲刷到浏览器
bw.flush();
bw.close();
br.close(); //阻塞十秒钟 相当于在执行请求时堵塞了
Thread.sleep(10000);
}catch (Exception ex){
ex.printStackTrace();
}
}
}
单线程调用
/**
* HTTP报文
* @author xin.qiliuhai 1045931706@qq.com
* @date 2018/4/29 9:09
*/
public class HttpDemo {
public static void main(String[] args) throws Exception {
ServerSocket ss = null;
Socket socket = null;
try {
//1.创建socket连接
ss = new ServerSocket(8080);
//循环等待
while (true) {
//2.堵塞,直到有新的连接进来
socket = ss.accept();
//3处理相应的请求,这个方法会堵塞
new HttpHandler(socket).run();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
ss.close();
}
}
}
大家可以尝试一下,第一次请求速度比较快,后面的请求必须至少等10秒才能进行,所以一旦请求处理
线程堵塞了会严重影响后面的请求,这个也是netty中一直强调的不要再主线程中调用耗时比较长的方法。
多线程版本1
/**
* @author xin.qiliuhai 1045931706@qq.com
* @date 2018/4/29 20:03
*/
public class HttpSimpleThread {
public static void main(String[] args)throws Exception{
//创建一个与CPU一样的的
ServerSocket ss = null;
Socket socket = null;
try {
while(true){
//1.创建socket连接
ss = new ServerSocket(8081);
//循环等待
while (true) {
socket=ss.accept();
//一个请求对应一个线程,请求直接交给线程进行处理
new Thread(new HttpHandler(socket)).start();
ss.close();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
ss.close();
}
}
}
每当来一个请求新建一个线程请求,但是我们知道一个电脑同时能处理的线程是十分有限的,创建与销毁线程
是需要占用一部分时间的,而且涉及到核心态与用户态之间的转换,我们可以理解一个请求时间=tcp时间+线程
创建时间+处理请求时间+销毁线程时间,那么有没有一种可能将线程创建与销毁时间做到忽略不计呢?答案是有的,
我们可以将处理请求的线程放到线程池中运行,这样减少很大一部分时间上的开销。
多线程版本2
/**
* @author xin.qiliuhai 1045931706@qq.com
* @date 2018/4/29 19:13
*/
public class HttpThreads {
public static void main(String[] args)throws Exception{
//创建一个与计算机线程数相同的不可变线程
Executor executor= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ServerSocket ss = null;
Socket socket = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
//1.创建socket连接
ss = new ServerSocket(8081);
//循环等待
while (true) {
socket=ss.accept();
//2.将线程放入到线程池中运行
executor.execute(new HttpHandler(socket));
//Thread.sleep(10000);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
ss.close();
}
}
}
当然在这里面的还有很多工作需要进行,比如当线程池满了,对新来的线程进行如何操作,对HTTP请求的解码与编码怎么处理
还有如果直到某个请求一定会占用比较长的时间怎么处理。这些将会在之后的文章进行讨论。
Http多线程版本的更多相关文章
- /MD、/MT、/LD( 使用 多线程版本 运行时库的C runtime library)
/MD./MT./LD(使用运行时库)(微软官网解释) Visual C++ 编译器选项 /MD./ML./MT./LD 区别 指定与你项目连接的运行期库 /MT多线程应用程序 /Mtd多线程应用程序 ...
- Python-爬取校花网视频(单线程和多线程版本)
一.参考文章 python爬虫爬取校花网视频,单线程爬取 爬虫----爬取校花网视频,包含多线程版本 上述两篇文章都是对校花网视频的爬取,由于时间相隔很久了,校花网上的一些视频已经不存在了,因此上述文 ...
- Python-爬取妹子图(单线程和多线程版本)
一.参考文章 Python爬虫之——爬取妹子图片 上述文章中的代码讲述的非常清楚,我的基本能思路也是这样,本篇文章中的代码仅仅做了一些异常处理和一些日志显示优化工作,写此文章主要是当做笔记,方便以后查 ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(26)|实战3:Http服务器(多线程版本)]
[易学易懂系列|rustlang语言|零基础|快速入门|(26)|实战3:Http服务器(多线程版本)] 项目实战 实战3:Http服务器 我们今天来进一步开发我们的Http服务器,用多线程实现. 我 ...
- Linux网络通信(TCP套接字编写,多进程多线程版本)
预备知识 源IP地址和目的IP地址 IP地址在上一篇博客中也介绍过,它是用来标识网络中不同主机的地址.两台主机进行通信时,发送方需要知道自己往哪一台主机发送,这就需要知道接受方主机的的IP地址,也就是 ...
- Java学习笔记(3)----网络套接字服务器多线程版本
本例给出一个客户端程序和一个服务器程序.客户端向服务器发送数据.服务器接收数据,并用它来生成一个结果,然后将这个结果返回给客户端.客户端在控制台上显示结果.在本例中,客户端发送的数据是圆的半径,服务器 ...
- c++ Socket客户端和服务端示例版本三(多线程版本)
客户端 #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/soc ...
- python多线程和多进程对比
1.多线程:开启一个进程test.py ,占用两个cpu 共占用45%左右(top -c ,按1) 多进程:开启两个进程test.py 用两个cpu 90%*2左右 test.py # codi ...
- python高性能代码之多线程优化
以常见的端口扫描器为实例 端口扫描器的原理很简单,操作socket来判断连接状态确定主机端口的开放情况. import socket def scan(port): s = socket.socket ...
随机推荐
- 赛码网算法: 军训队列( python实现 )
军训队列 题目描述某大学开学进行军训队列训练,将学生从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列剩下的依次向前靠拢,再从头开始进行一至三报数,凡报到三的出 ...
- 32位centos6.5 mysql rpm包下载
查看centos版本号和位数: http://www.cnblogs.com/grey-wolf/p/7472507.html mysql下载: 1.进入https://dev.mysql.com/d ...
- Mybatis自动生成Xml文件,针对字段类型为text等会默认产生XXXXWithBlobs的方法问题
默认情况下产生的Mapper.xml里面存在: 需要修改generatorConfiguration.xml,里面的table加属性,如: <table domainObjectName=&qu ...
- POJ-3723 Conscription---最大权森林---最小生成树
题目链接: https://vjudge.net/problem/POJ-3723 题目大意: 需要征募女兵N人, 男兵M人. 每征募一个人需要花费10000美元. 带式如果已经征募的人中有一些关系亲 ...
- Java调用SQL脚本执行的方案
在Java中调用SQL脚本的方式有多种,在这里只记录一种自己常用的方式,个人觉得挺实用方便的. 运用ScriptRunner这个类. import org.apache.ibatis.io.Resou ...
- 音频压缩编码 opus 附完整C++代码示例
绝大数人都知道mp3格式编码,以及aac,amr等压缩格式编码. 而在语音通信界有一个强悍的音频格式编码opus. 经过实测,压缩比最高可以达到1:10. 100KB 压缩后 10KB 虽然是有损压缩 ...
- C#使用AutoMapper6.2.2.0进行对象映射
先说说DTO DTO是个什么东东? DTO(Data Transfer Object)就是数据传输对象,说白了就是一个对象,只不过里边全是数据而已. 为什么要用DTO? 1.DTO更注重数据,对领域对 ...
- jq跨域获取json
<!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" ...
- js 一些基础的理解
javascript(JS)的组成? DOM 文档对象模型 BOM 浏览器对象模型 ECMAScript javascript(JS)在页面中处理了什么事情? 特效交互 数据交互 逻辑操作 常见特效的 ...
- Spring Boot 之Hello Word
Spring Boot官网:http://projects.spring.io/spring-boot/ 环境准备:maven 3.3.5.jdk8.Idea 1.创建maven项目工程 2.引入st ...