writedby 张艳涛

长连接是HTTP/1.1的特征之一,1.1出现的原因是因为一个客户请求一个网页,这是一个http请求,这个网页中如果有图片,那么也会变为一个http请求,对于java客户端,一个http请求

是通过socket.getinputstream.cast(PrintWriter).println("http请求头"),如果俩个请求都通过一个socket来写数据,那么这个就是http长连接,如果你写一个简单http服务器,那你实现的就不是长连接,每次请求都把socket.close()了,

所以判断一个http请求时不是长连接就是判断socket.close有没有执行

那么我们来看tomcat是如何实现长连接了的,对应深入理解tomcat第4章

实现思路是,如果socket不断开的话,那么socket.getInputStream(),得到的in流 会调用in.read()方法,进行阻塞,如果来了数据,读取新进来的请求,如果满足http协议进行解析;

 HttpProcessor类
public void run() { // Process requests until we receive a shutdown signal
while (!stopped) { // Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue; // Process the request from this socket
try {
process(socket);
} catch (Throwable t) {
log("process.invoke", t);
} // Finish up this request
connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
} }

进入方法

    private void process(Socket socket) {
boolean ok = true;
boolean finishResponse = true;
SocketInputStream input = null;
OutputStream output = null; // Construct and initialize the objects we will need
try {
input = new SocketInputStream(socket.getInputStream(),
connector.getBufferSize());
} catch (Exception e) {
log("process.create", e);
ok = false;
} keepAlive = true; while (!stopped && ok && keepAlive) { finishResponse = true; try {
request.setStream(input);
request.setResponse(response);
output = socket.getOutputStream();
response.setStream(output);
response.setRequest(request);
((HttpServletResponse) response.getResponse()).setHeader
("Server", SERVER_INFO);
} catch (Exception e) {
log("process.create", e);
ok = false;
} // Parse the incoming request
try {
if (ok) { parseConnection(socket);
parseRequest(input, output);
if (!request.getRequest().getProtocol()
.startsWith("HTTP/0"))
parseHeaders(input);
if (http11) {
// Sending a request acknowledge back to the client if
// requested.
ackRequest(output);
// If the protocol is HTTP/1.1, chunking is allowed.
if (connector.isChunkingAllowed())
response.setAllowChunking(true);
} }
异常...略
} // Finish up the handling of the request
if (finishResponse) {
try {
response.finishResponse();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
request.finishRequest();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
if (output != null)
output.flush();
} catch (IOException e) {
ok = false;
}
} // We have to check if the connection closure has been requested
// by the application or the response stream (in case of HTTP/1.0
// and keep-alive).
if ( "close".equals(response.getHeader("Connection")) ) {
keepAlive = false;
} // End of request processing
status = Constants.PROCESSOR_IDLE; // Recycling the request and the response objects
request.recycle();
response.recycle(); } try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log("process.invoke", e);
}
socket = null; }

进入方法

  input.readRequestLine(requestLine);

接着进入

public void readRequestLine(HttpRequestLine requestLine)
throws IOException { // Recycling check
if (requestLine.methodEnd != 0)
requestLine.recycle(); // Checking for a blank line
int chr = 0;
do { // Skipping CR or LF
try {
chr = read();
} catch (IOException e) {
chr = -1;
}
} while ((chr == CR) || (chr == LF));
if (chr == -1)
throw new EOFException
(sm.getString("requestStream.readline.error"));
pos--; // Reading the method name

接着进入

    public int read()
throws IOException {
if (pos >= count) {//读到了结尾
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;
}

接着

    /**
* Fill the internal buffer using data from the undelying input stream.
*/
protected void fill()
throws IOException {
pos = 0;
count = 0;
int nRead = is.read(buf, 0, buf.length);
if (nRead > 0) {
count = nRead;
}
}
parseRequest(input, output);

//input的构造方法
input = new SocketInputStream(socket.getInputStream(),
connector.getBufferSize()); //
public SocketInputStream(InputStream is, int bufferSize) { this.is = is;
buf = new byte[bufferSize]; }

上述俩个方法中的fill() 的is.read() 底层就是socket.getInputStream进行读到缓冲区

这个方法是有阻塞的,那么就实现了处理完一个http请求,接着读取第二个请求

如果以上过程报错,跳出while循环

        try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log("process.invoke", e);
}
socket = null;

关闭socket,那么就断开了socket长连接

此文结束

最新文章

  1. PHP 单引号 与双引号区别
  2. hdu 2896 AC自动机
  3. java 程序中添加socks 5代理
  4. WeX5学习笔记-创建本地APP相关问题
  5. Linux命令:ps / top
  6. Using Amazon API Gateway with microservices deployed on Amazon ECS
  7. poj: 2255
  8. 剑指OFFER之矩形覆盖(九度OJ1390)
  9. linux下nagios的安装与部署
  10. Linux kernel ‘lbs_debugfs_write’函数数字错误漏洞
  11. HDOJ-ACM1006(JAVA)
  12. android分享到新浪微博,认证+发送微博,
  13. Openlays 3 绘制基本图形
  14. 关于Client_Abort_Exception异常的分析和解决
  15. Java 中判断类和实例之间的关系
  16. tcpdump 使用
  17. webservice接口,用Soapui
  18. Python字典(Dictionary)
  19. libnids使用 (转)
  20. 在谈PHP中的 抽象类(abstract class)和 接口(interface)

热门文章

  1. SQL中的分组之后TOPN问题
  2. 搭建DG(data guard),及搭建过程中遇到的一些小问题
  3. 『无为则无心』Python基础 — 6、Python的注释
  4. ANDROID开发 Fatal signal 11(SIGSEGV) at 0x问题解决方案
  5. 冷饭新炒 | 深入Quartz核心运行机制
  6. 服务器通信REST、gRPC,Swagger/OpenAPI,Consul
  7. centos7 安装最新的 wiki confluence
  8. Linux系统下安装NodeJS
  9. SpringCloud:Feign调用接口不稳定问题以及如何设置超时
  10. 线程中的join()