Go实现FastCgi Proxy Client 系列(四) keep

Stella981
• 阅读 703

先贴几个链接

前三篇

Go实现FastCgi Proxy Client 系列(三)

Go实现FastCgi Proxy Client 系列(二)

Go实现FastCgi Proxy Client 系列(一)

灵感帖

TCP keepalive 和 http keep-alive

FastCGI Specification

Golang 优化之路——HTTP长连接

go HTTP Client大量长连接保持

很感谢上面几个文章,让我突然想通了我之前一直没搞懂的问题,虽然问题不是一种,但是也算是旁敲侧击的让我茅塞顿开了,非常感谢!

分析

协议

麻省理工学院的文档上是这么描述的:

The flags component contains a bit that controls connection shutdown:

flags & FCGI_KEEP_CONN: If zero, the application closes the connection after responding to this request. If not zero, the application does not close the connection after responding to this request; the Web server retains responsibility for the connection.

好吧,高大上的描述。各种文档里对fastcgi协议里没怎么讲keep-alive的作用,就只是很简单的说了,如果是开启了,就能让http连接进行复用。然而按照之前的知识(我没跟上时代啊),http协议是无状态的协议,死活我也是想不通如何连接复用。

然而我忘记了,http也是基于tcp协议的,tcp一般而言,如果你不手动进行断开,或者网络原因引起的话,是会保持一个长连接的(通常都会设置超时)。

盗张图:

Go实现FastCgi Proxy Client 系列(四) keep

可以看出,假如,我们不进行最后的4次挥手操作,在超时范围内,这个tcp连接是不会断开的。

代码

然后我再去看go官方对fastcgi协议的实现,我发现一个很重要的地方(源码位置 net/http/fastcgi/child.go):

当用户发起终止信号的时候,keep-alive起了作用,那就是说,我的proxy层只要不进行断开连接,这个tcp连接就依然还是可用的。

case typeAbortRequest:
        //......
        if !req.keepConn {
            // connection will close upon return
            return errCloseConn
        }
        return nil

然后,我继续阅读源码,此时,我要唱一下,“终于等到你,还好我没忘记”。果然是这样,如果链接不是keep-alive,会即时关闭tcp连接。

func (c *child) serveRequest(req *request, body io.ReadCloser) {
    //......

    if !req.keepConn {
        c.conn.Close()
    }
}

修改实现

在我们读取数据的位置,我们进行相关操作即可,如果,请求不是keep-alive 自然,返回值会包含终止符 EOF,这时可以直接返回;反之,如果是keep-alive,则会每个请求都获得到一个typeEndRequest(值为3,具体请看第一篇)的标识

// recive untill EOF or FCGI_END_REQUEST
    for {
        err1 = rec.read(cgi.rwc)
        //if !keep-alive the end has EOF
        if err1 != nil {
            if err1 != io.EOF {
                err = err1
            }
            break
        }

        switch {
        case rec.h.Type == typeStdout:
            retout = append(retout, rec.content()...)
        case rec.h.Type == typeStderr:
            reterr = append(reterr, rec.content()...)
        case rec.h.Type == typeEndRequest:
            //if keep-alive
            //It's had return
            //But connection Not close
            retout = append(retout, rec.content()...)
            return
        default:
            //fallthrough
        }
    }

总结

个人总结

那,其实很简单不是嘛?我之前只是理解错了typeEndRequest这个类型,我把他当成了错误的时候才会返回,报了一个fallthrough。更简单的一句就是,复用的不是http,不是http,不是!复用的tcp!tcp!tcp!

然后,当遇到一个自己暂时无法理解的问题时候,可能你已经钻入了死胡同。这个时候,你可以放松自己精神,玩玩游戏,运动运动都行(哈哈,这个问题我都忘记一个月了,感谢群友的问题,虽然我没帮他解决,但是他提示了我,我还要没解决的问题)。

下一步

下一步,将会对超时进行设置。

spinx(小玩具)

一个实现对fastcgi协议的转发小玩具。

Quick Start

go get github.com/lwl1989/spinx

cd $gopath/src/github.com/lwl1989/spinx

go build -o spinx main.go

Install

sudo ./spinx  -c=config_path install

Remove

sudo ./spinx  remove

Start

sudo ./spinx start
or
./spinx -d=false -c=config_path

Stop

sudo ./spinx stop
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
2年前
RxJS的另外四种实现方式(后记)—— 同时实现管道和链式编程
目录RxJS的另外四种实现方式(序)(https://my.oschina.net/langhuihui/blog/2051754)RxJS的另外四种实现方式(一)——代码最小的库(https://my.oschina.net/langhuihui/blog/2051770)RxJS的另外四种实现方式(二)——代码最小的库(续)
Wesley13 Wesley13
2年前
java多线程——锁
这是多线程系列第四篇,其他请关注以下:java多线程—线程怎么来的?(https://my.oschina.net/u/1859679/blog/1517807)java多线程内存模型(https://my.oschina.net/u/1859679/blog/1525343)java多线程——volatile
Stella981 Stella981
2年前
Spring Cloud 系列之 Config 配置中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:SpringCloud系列之Config配置中心(一)(https://my.oschina.net/u/4126211/blog/4274304)本篇文章讲解Config如何实现配置中心自动刷新。配置中心自动刷新  点击链接观看:配置中心自动刷新视频(http
Stella981 Stella981
2年前
Go实现FastCgi Proxy Client 系列(一)
什么是FastCgi再了解FastCgi之前,我们一定要先知道,什么叫Cgi。CGI全称是“通用网关接口”(CommonGatewayInterface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序一般运行在网络服务器上。CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。
Easter79 Easter79
2年前
SwiftUI直通车系列(5)—— 自定义绘制
SwiftUI直通车系列(5)——自定义绘制前情回顾:SwiftUI直通车系列(1)——视图的布局与组织(https://my.oschina.net/u/2340880/blog/4529951)SwiftUI直通车系列(2)——列表视图(https://my.oschina.net
Stella981 Stella981
2年前
Go实现FastCgi Proxy Client 系列(三)优化篇
墨迹一点个人琐碎最近比较忙,以致于很久都没有写blog了,但是,golang的水平自认为是总算入门了。协程的个人理解网上的说法一般都是协程是轻量级线程。我个人认为协程的好处1.小2.无需在用户态和内核态切换(完全在用户态)3.无需线程上下文切换的开销(因为之上的好处)4.编码简单(原
Wesley13 Wesley13
2年前
@Enable驱动逻辑
这个系列分为5篇1\.@Component,@Service等注解是如何被解析的(https://my.oschina.net/floor/blog/4325651)2\.@Enable驱动原理(https://my.oschina.net/floor/blog/4333081)3\.@EnableAutoConfiguratio
Wesley13 Wesley13
2年前
GOJS使用
GOJS使用前端拓扑图1.基础版:引入go.js<scriptsrc"https://my.oschina.net//u/4402671/blog/3234986/js/go.js"type"text/javascript"</script
Wesley13 Wesley13
2年前
(5) 基于领域分析设计的架构规范
本系列目录:1.改变与优势(https://my.oschina.net/u/4006523/blog/3071568)2.领域分析基础(https://my.oschina.net/u/4006523/blog/3071569)3.读写隔离(https://my.oschina.net/u/4006523/blog/3071
Wesley13 Wesley13
2年前
PHP扩展开发(一)
入门1.下载PHP源码(我的版本是5.6.13)2.常规编译安装可以看我以前的blog(http://my.oschina.net/lwl1989/blog/511295)3.使用ext_skelcdphpsrc/ext./ext_skelextname