过早客
  • 首页
  • 节点
  • 成员
  • 广告投放
  • 登录
  • 注册

golang解析IP到城市jsonRPC服务

IT技术 • dejavuzhou • 发表于 7 年前 • 最后回复来自 dejavuzhou • 7 年前

RESTful接口

请求URL:
- https://api.xxx.com/xxx/v1/ip2addr?ip=219.140.227.235

请求方式:
- GET

参数

参数名 类型 说明
ip url-qurey-string 可选 要查询的ip地址,如果不传这表示当前的ip

返回示例

{
    "code": 1,
    "data": {
        "Country": "中国",
        "Province": "湖北省",
        "City": "武汉",
        "ISP": "",
        "Latitude": 30.5801,
        "Longitude": 114.2734,
        "TimeZone": "Asia/Shanghai"
    },
    "ip": "219.140.227.235"
}

json_rpc 协议:tcp 地址: 121.40.238.123(IP地址更快) api.mojotv.cn 端口: 3344


第三方资源

  • GeoIP2 Reader for Go
  • GeoLite2 开源数据库

go标准库jsonRPC服务端

Go官方提供了一个RPC库: net/rpc。包rpc提供了通过网络访问一个对象的方法的能力。服务器需要注册对象, 通过对象的类型名暴露这个服务。注册后这个对象的输出方法就可以远程调用,这个库封装了底层传输的细节,包括序列化。服务器可以注册多个不同类型的对象,但是注册相同类型的多个对象的时候回出错。
* 方法的类型是可输出的 (the method's type is exported)
* 方法本身也是可输出的 (the method is exported)
* 方法必须由两个参数,必须是输出类型或者是内建类型 (the method has two arguments, both exported or builtin types)
* 方法的第二个参数是指针类型 (the method's second argument is a pointer)
* 方法返回类型为 error (the method has return type error)

package main

import (
    "fmt"
    "github.com/oschwald/geoip2-golang"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
    "os"
    "log"
)
//返回值结构体
//需要满足以上要求
type Response struct {
    Country   string
    Province  string
    City      string
    ISP       string
    Latitude  float64
    Longitude float64
    TimeZone  string
}

type Ip2addr struct {
    db *geoip2.Reader
}
//参数结构体
//需要满足以上要求
type Agrs struct {
    IpString string
}
//json rpc 处理请求
//需要满足以上要求
func (t *Ip2addr) Address(agr *Agrs, res *Response) error {
    netIp := net.ParseIP(agr.IpString)
    record, err := t.db.City(netIp)
    res.City = record.City.Names["zh-CN"]
    res.Province = record.Subdivisions[0].Names["zh-CN"]
    res.Country = record.Country.Names["zh-CN"]
    res.Latitude = record.Location.Latitude
    res.Longitude = record.Location.Longitude
    res.TimeZone = record.Location.TimeZone
    return err
}

func main() {
         //加载geoIp数据库
    db, err := geoip2.Open("./GeoLite2-City.mmdb")
    if err != nil {
        log.Fatal(err)
    }
        //初始化jsonRPC
    ip2addr := &Ip2addr{db}
       //注册
    rpc.Register(ip2addr)
       //绑定端口
    address := ":3344"
    tcpAddr, err := net.ResolveTCPAddr("tcp", address)
    checkError(err)
    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    log.Println("json rpc is listening",tcpAddr)
    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        jsonrpc.ServeConn(conn)
    }

}

func checkError(err error) {
    if err != nil {
        fmt.Println("Fatal error ", err.Error())
        os.Exit(1)
    }
}

PHP-jsonRPC客户端

class JsonRPC
{
    public $conn;

    function __construct($host, $port)
    {
        $this->conn = fsockopen($host, $port, $errno, $errstr, 3);
        if (!$this->conn) {
            return false;
        }
    }

    public function Call($method, $params)
    {
        $obj = new stdClass();
        $obj->code = 0;

        if (!$this->conn) {
            $obj->info = "jsonRPC连接失败!请联系eric@mojotv.cn";
            return $obj;
        }
        $err = fwrite($this->conn, json_encode(array(
                'method' => $method,
                'params' => array($params),
                'id' => 0,
            )) . "\n");
        if ($err === false) {
            fclose($this->conn);
            $obj->info = "jsonRPC发送参数失败!socket-tcp资源是否释放";
            return $obj;
        }

        stream_set_timeout($this->conn, 0, 3000);
        $line = fgets($this->conn);
        fclose($this->conn);
        if ($line === false) {
            $obj->info = "jsonRPC返回消息为空!请检查自己的rpc-client代码";
            return $obj;
        }
        $temp = json_decode($line);
        $obj->code = $temp->error == null ? 1 : 0;
        $obj->data = $temp->result;
        return $obj;
    }
}


function json_rpc_ip_address($ipString)
{
    $client = new JsonRPC("127.0.0.1", 3344);
    $obj = $client->Call("Ip2addr.Address", ['IpString' => $ipString]);
    return $obj;
}

go语言jsonRPC客户端

package main

import (
    "fmt"
    "log"
    "net/rpc/jsonrpc"
)

type Response struct {
    Country   string
    Province  string
    City      string
    ISP       string
    Latitude  float64
    Longitude float64
    TimeZone  string
}
type Agrs struct {
    IpString string
}
func main() {
    client, err := jsonrpc.Dial("tcp", "121.40.238.123:3344")
    if err != nil {
        log.Fatal("dialing:", err)
    }
    // Synchronous call
    var res Response
    err = client.Call("Ip2addr.Address", Agrs{"219.140.227.235"}, &res)
    if err != nil {
        log.Fatal("arith error:", err)
    }
    fmt.Println(res)

}
加入收藏 新浪微博 分享到微信 ❤赞 3165 次点击 1 人赞 3 人收藏

打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮

共收到7条回复
homani 7 年前 #1 赞 1

正在学golang,多谢分享

jack155 7 年前 #2 赞 1

学习了

dejavuzhou 楼主 7 年前 #3 赞 0

@jack155 @homani golang-rpc教程 这个教程有一点点错误. 正确的是: 必须是输出类型或者是内建类型 (the method has two arguments, both exported or builtin types) 而教程里面说的是错误的:必须有两个导出类型的参数:

stephendanteng 7 年前 #4 赞 0

我司是C代码。。差本地IP库。。你这网络查询,请求频率高了根本扛不住吧老哥。

dejavuzhou 楼主 7 年前 #5 赞 0

@stephendanteng 本地ip库可以取geoIP下载
你可以配合其他语言使用这个ip数据库

小作坊 不知道高并发是何物 只会堆硬件 LOL

stephendanteng 7 年前 #6 赞 0

@dejavuzhou 我们也是小作坊,做的时候找了好些库,最后临时先用的ipip.net的免费版 ,虽然也不是很全 ,目前还是有人维护,定期更新。。。后面 如果要做精准点,就把几个库整合一波。

dejavuzhou 楼主 7 年前 #7 赞 0

@stephendanteng ipip.ne 看起来也不错

请绑定手机号后,再发言,点击此处
Guozaoke.com—源自武汉的高端交流分享社区
相关主题
我没房子的时候,每年赚的钱比不上房子每年涨的钱。等我咬牙买了,每年赚的钱,比不上房子每年亏的钱
有多少人知道华为在AI算力的基础建设上已经超越英伟达了?
开发了一个管理 Linux 服务器的桌面可视化管理工具,求蹂躏
社区里有没有对钢架自行车和钢架builder感兴趣的同志
Android手机推荐
社友们,车险异地投保有了解的吗
为什么手机没有把投影仪这个市场给兼并了呢?
最近时间少了, 隔了这么久, 才做了一个网站
华为麒麟X90用5nm工艺
服务器可视化采用纯前端渲染,这个技术实现难度如何

过早客微信公众号:guozaoke • 过早客新浪微博:@过早客 • 广告投放合作微信:fullygroup50 鄂ICP备2021016276号-2 • 鄂公网安备42018502001446号