博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解 IPFS - 分布式代理
阅读量:4098 次
发布时间:2019-05-25

本文共 4128 字,大约阅读时间需要 13 分钟。

今天我们利用 libp2p 创建一个简单的分布式 http 代理,具体 demo 参见官方 example: https://github.com/libp2p/go-libp2p-examples/blob/master/http-proxy/proxy.go

代理,同学们都很熟悉,不管是写爬虫,还是开发服务器,都或多或少的接触过。

本质上就是通过一个中间节点转发流量到目标地址。libp2p 也是一样,不过对他来说,每个节点都是平等的,理论上都可以作为客户端或者代理。另外他底层的 stream 模块也让开发变的更加容易。

12345678910
XX  XXXXXX                                                                                                  X         XX                                                                                        XXXXXXX  XX          XX XXXXXXXXXX                  +----------------+                +-----------------+              XXX      XXX            XXX        XXX HTTP Request     |                |                |                 |             XX                                    XX+----------------->                | libp2p stream  |                 |  HTTP       X                                      X                  |  Local peer    <---------------->  Remote peer    <------------->     HTTP SERVER - THE INTERNET      XX<-----------------+                |                |                 | Req & Resp   XX                                   X  HTTP Response   |  libp2p host   |                |  libp2p host    |               XXXX XXXX XXXXXXXXXXXXXXXXXXXX   XXXX                  +----------------+                +-----------------+                                            XXXXX

为了能够代理一个请求,我们需要先创建一个本地节点监听 localhost:9900 。HTTP requests 通过 libp2p stream 模块打到远程节点。远程节点发起 http 请求,并将 response 返回给本地节点,本地节点再中继返回给客户端。

(一)远程节点

首先我们需要建立一个 libp2p 远程节点

1234567
func makeRandomHost(port int) host.Host {	host, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)))	if err != nil {		log.Fatalln(err)	}	return host}

接下来需要为节点监听端口绑定 handler

123456789101112131415161718192021222324252627282930313233343536373839404142
// Protocol 自己约定,为了能和 handler 匹配上host.SetStreamHandler(Protocol, streamHandler)func streamHandler(stream network.Stream) {	defer stream.Close()      // 接收本地结果过来的请求   // 从 stream 中读取 request 的 data	buf := bufio.NewReader(stream)	// Read the HTTP request from the buffer	req, err := http.ReadRequest(buf)	if err != nil {		stream.Reset()		return	}	defer req.Body.Close()		// 重置一些 http 字段	req.URL.Scheme = "http"	hp := strings.Split(req.Host, ":")	if len(hp) > 1 && hp[1] == "443" {		req.URL.Scheme = "https"	} else {		req.URL.Scheme = "http"	}	req.URL.Host = req.Host	outreq := new(http.Request)	*outreq = *req  // 发起请求到目标地址	resp, err := http.DefaultTransport.RoundTrip(outreq)	if err != nil {		stream.Reset()		log.Println(err)		return	}		// 将 resp 写回到 stream	resp.Write(stream)}
(二)本地节点

本地节点需要能处理 http 请求,然后将请求转发给远程节点

1234567891011121314151617181920212223242526272829
// ServeHTTP 实现了 http.Handler 的接口func (p *ProxyService) ServeHTTP(w http.ResponseWriter, r *http.Request) {	fmt.Printf("proxying request for %s to peer %s\n", r.URL, p.dest.Pretty())	// 将 request 请求发送到远程节点	stream, _ := p.host.NewStream(context.Background(), p.dest, Protocol)		defer stream.Close()	// r.Write() 将 http 请求数据写入到 stream 里面	_ = r.Write(stream)		// 将 remote response 写回到 http response 里面	buf := bufio.NewReader(stream)	resp, _ := http.ReadResponse(buf, r)		// 写 headers	for k, v := range resp.Header {		for _, s := range v {			w.Header().Add(k, s)		}	}  // 写 StatusCode	w.WriteHeader(resp.StatusCode)	// 最后 copy body	io.Copy(w, resp.Body)	resp.Body.Close()}

具体代码见:https://github.com/libp2p/go-libp2p-examples/blob/master/http-proxy/proxy.go

(三) 运行
build
123
> make deps> cd http-proxy/> go build
run
  1. 首先我们运行 remote 节点

    1234
    > ./http-proxyProxy server is readylibp2p-peer addresses:/ip4/127.0.0.1/tcp/12000/p2p/QmddTrQXhA9AkCpXPTkcY7e22NK73TwkUms3a44DhTKJTD
  2. 然后运行本地节点 -d 参数后面就是上面运行的 remote 节点的地址

    12345
    > ./http-proxy -d /ip4/127.0.0.1/tcp/12000/p2p/QmddTrQXhA9AkCpXPTkcY7e22NK73TwkUms3a44DhTKJTDProxy server is readylibp2p-peer addresses:/ip4/127.0.0.1/tcp/12001/p2p/Qmaa2AYTha1UqcFVX97p9R1UP7vbzDLY7bqWsZw1135QvNproxy listening on  127.0.0.1:9900
  3. 本地代理监听 127.0.0.1:9900, 我们用 curl 命令请求下看看效果

12
> curl -x "127.0.0.1:9900" "http://ipfs.io/p2p/QmfUX75pGRBRDnjeoMkQzuQczuCup2aYbeLxz5NzeSu9G6"it works!

转载地址:http://fkmii.baihongyu.com/

你可能感兴趣的文章
【UGUI/NGUI】一键换Text/Label字体
查看>>
【C#】身份证本地验证
查看>>
【Unity】坑爹的Bug
查看>>
【算法】求数组中某两个数的和为目标值
查看>>
如何高效学习动态规划?
查看>>
动态规划法(六)鸡蛋掉落问题(一)
查看>>
LeetCode 887.鸡蛋掉落(C++)
查看>>
奇异值分解(SVD)的原理详解及推导
查看>>
算法数据结构 思维导图学习系列(1)- 数据结构 8种数据结构 数组(Array)链表(Linked List)队列(Queue)栈(Stack)树(Tree)散列表(Hash)堆(Heap)图
查看>>
【机器学习】机器学习系统SysML 阅读表
查看>>
最小费用最大流 修改的dijkstra + Ford-Fulksonff算法
查看>>
最小费用流 Bellman-Ford与Dijkstra 模板
查看>>
实现高性能纠删码引擎 | 纠删码技术详解(下)
查看>>
scala(1)----windows环境下安装scala以及idea开发环境下配置scala
查看>>
zookeeper(3)---zookeeper API的简单使用(增删改查操作)
查看>>
zookeeper(4)---监听器Watcher
查看>>
zookeeper(2)---shell操作
查看>>
mapReduce(3)---入门示例WordCount
查看>>
hbase(3)---shell操作
查看>>
hbase(1)---概述
查看>>