zoukankan      html  css  js  c++  java
  • 分布式爬虫

    RPC基本概念

    RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

    • RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务
    • 本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定。
    • 远程过程调用:上述操作的过程中,如果addAge()这个方法在服务端,执行函数的函数体在远程机器上,如何告诉机器需要调用这个方法呢?
    1. 首先客户端需要告诉服务器,需要调用的函数,这里函数和进程ID存在一个映射,客户端远程调用时,需要查一下函数,找到对应的ID,然后执行函数的代码。
    2. 客户端需要把本地参数传给远程函数,本地调用的过程中,直接压栈即可,但是在远程调用过程中不再同一个内存里,无法直接传递函数的参数,因此需要客户端把参数转换成字节流,传给服务端,然后服务端将字节流转换成自身能读取的格式,是一个序列化和反序列化的过程。
    3. 数据准备好了之后,如何进行传输?网络传输层需要把调用的ID和序列化后的参数传给服务端,然后把计算好的结果序列化传给客户端,因此TCP层即可完成上述过程。
      总结一下上述过程:
    // Client端 
    //    Student student = Call(ServerAddr, addAge, student)
    1. 将这个调用映射为Call ID。
    2. 将Call ID,student(params)序列化,以二进制形式打包
    3. 把2中得到的数据包发送给ServerAddr,这需要使用网络传输层
    4. 等待服务器返回结果
    5. 如果服务器调用成功,那么就将结果反序列化,并赋给student,年龄更新
    
    // Server端
    1. 在本地维护一个Call ID到函数指针的映射call_id_map,可以用Map<String, Method> callIdMap
    2. 等待客户端请求
    3. 得到一个请求后,将其数据包反序列化,得到Call ID
    4. 通过在callIdMap中查找,得到相应的函数指针
    5. 将student(params)反序列化后,在本地调用addAge()函数,得到结果
    6. 将student结果序列化后通过网络返回给Client
    

    RPC简单的测试

    rpc.go

    package rpcdemo
    
    import (
    	"errors"
    )
    
    type DemoService struct {}
    
    type Args struct {
    	A, B int
    }
    
    func (DemoService) Div(args Args, result *float64) error  {
    	if args.B == 0 {
    		return errors.New("division by zero")
    	}
    	*result = float64(args.A) / float64(args.B)
    	return nil
    }
    
    

    service/main.go

    package main
    
    import (
    	rpcdemo "learn/rpc"
    	"log"
    	"net"
    	"net/rpc"
    	"net/rpc/jsonrpc"
    )
    //开启一个服务器,监听1234端口,等待客户端请求
    func main() {
    	rpc.Register(rpcdemo.DemoService{})
    	listener, err := net.Listen("tcp", ":1234")
    	if err != nil {
    		panic(err)
    	}
    	for {
    		conn, err := listener.Accept()
    		if err != nil {
    			log.Printf("accept error: %v", err.Error())
    			continue
    		}
    		go jsonrpc.ServeConn(conn)
    	}
    }
    
    

    client/main.go

    package main
    
    import (
    	"fmt"
    	rpcdemo "learn/rpc"
    	"net"
    	"net/rpc/jsonrpc"
    )
    //请求服务端
    func main() {
    	conn, err := net.Dial("tcp", ":1234")
    	if err != nil {
    		panic(err)
    	}
    	client := jsonrpc.NewClient(conn)
    	var result float64
    	//传入需要请求的函数名和值
    	err = client.Call("DemoService.Div", rpcdemo.Args{10, 3}, &result)
    	if err != nil {
    		fmt.Println(err)
    	}else {
    		fmt.Println(result)
    	}
    	err = client.Call("DemoService.Div", rpcdemo.Args{10, 0}, &result)
    	if err != nil {
    		fmt.Println(err)
    	}else {
    		fmt.Println(result)
    	}
    }
    
    

    输出结果:

    实现

    https://github.com/cwyfengyiyuan/golang-crawler.git

  • 相关阅读:
    Oracle merge
    ORA-1461 encountered when generating server alert SMG-3500
    COALESCE NVL NVL2 DECODE
    oracle限制ip訪問
    java动态代理实现与原理详细分析
    MySql/Oracle树形结构查询
    微信公众号Java接入demo
    支付宝转账
    支付宝 查看订单 退款
    linux网络编程--UNIX域套接字
  • 原文地址:https://www.cnblogs.com/chenwenyin/p/12425154.html
Copyright © 2011-2022 走看看