server.go 源码阅读
package pingo
import (
"bufio"
"bytes"
"flag"
"fmt"
"io"
"math/rand"
"net"
"net/rpc"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"time"
)
// Register a new object this plugin exports. The object must be
// an exported symbol and obey all rules an object in the standard
// "rpc" module has to obey.
//注册的一个对象作为可以导出对象。这个对象必须符合RPC规则
// - exported method of exported type
// - two arguments, both of exported type
// - the second argument is a pointer
// - one return value, of type error
// Register will panic if called after Run.
//如果在运行中 注册对象 就会报错
func Register(obj interface{}) {
if defaultServer.running {
panic("Do not call Register after Run")
}
defaultServer.register(obj)//注册可导出的对象
}
// Run will start all the necessary steps to make the plugin available.
//调用Run函数是必须的来保证插件的可用性
func Run() error {
if !flag.Parsed() {//判断参数是否解析
flag.Parse()//解析当前参数
}
return defaultServer.run()
}
// Internal object for plugin control
type PingoRpc struct{}
// Default constructor for interal object. Do not call manually.
func NewPingoRpc() *PingoRpc {
return &PingoRpc{}
}
// Internal RPC call to shut down a plugin. Do not call manually.
func (s *PingoRpc) Exit(status int, unused *int) error {
os.Exit(status)
return nil
}
type config struct {
proto string
addr string
prefix string
unixdir string
}
func makeConfig() *config {
c := &config{}
flag.StringVar(&c.proto, "pingo:proto", "unix", "Protocol to use: unix or tcp")
flag.StringVar(&c.unixdir, "pingo:unixdir", "", "Alternative directory for unix socket")
flag.StringVar(&c.prefix, "pingo:prefix", "pingo", "Prefix to output lines")
return c
}
type rpcServer struct {
*rpc.Server
secret string
objs []string
conf *config
running bool
}
func newRpcServer() *rpcServer {
rand.Seed(time.Now().UTC().UnixNano())
r := &rpcServer{
Server: rpc.NewServer(),
secret: randstr(64),
objs: make([]string, 0),
conf: makeConfig(), // conf remains fixed after this point
}
r.register(&PingoRpc{})
return r
}
var defaultServer = newRpcServer()
type bufReadWriteCloser struct {
*bufio.Reader
r io.ReadWriteCloser
}
func newBufReadWriteCloser(r io.ReadWriteCloser) *bufReadWriteCloser {
return &bufReadWriteCloser{Reader: bufio.NewReader(r), r: r}
}
func (b *bufReadWriteCloser) Write(data []byte) (int, error) {
return b.r.Write(data)
}
func (b *bufReadWriteCloser) Close() error {
return b.r.Close()
}
func readHeaders(brwc *bufReadWriteCloser) ([]byte, error) {
var buf bytes.Buffer
var headerEnd bool
for {
b, err := brwc.ReadByte()
if err != nil {
return []byte(""), err
}
buf.WriteByte(b)
if b == '\n' {
if headerEnd {
break
}
headerEnd = true
} else {
headerEnd = false
}
}
return buf.Bytes(), nil
}
func parseHeaders(brwc *bufReadWriteCloser, m map[string]string) error {
headers, err := readHeaders(brwc)
if err != nil {
return err
}
r := bytes.NewReader(headers)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
parts := strings.SplitN(scanner.Text(), ": ", 2)
if parts[0] == "" {
continue
}
m[parts[0]] = parts[1]
}
return nil
}
func (r *rpcServer) authConn(token string) bool {
if token != "" && token == r.secret {
return true
}
return false
}
func (r *rpcServer) serveConn(conn io.ReadWriteCloser, h meta) {
bconn := newBufReadWriteCloser(conn)
defer bconn.Close()
headers := make(map[string]string)
if err := parseHeaders(bconn, headers); err != nil {
h.output("error", err.Error())
return
}
if r.authConn(headers["Auth-Token"]) {
r.Server.ServeConn(bconn)
}
return
}
func (r *rpcServer) register(obj interface{}) {
element := reflect.TypeOf(obj).Elem() //获取对象元素类型
r.objs = append(r.objs, element.Name()) //添加到objs中 获取元素类型名称
r.Server.Register(obj)//调用rpc 的注册方法
}
type connection interface {
addr() string
retries() int
}
type tcp int
func (t *tcp) addr() string {
if *t < 1024 {
// Only use unprivileged ports
*t = 1023
}
*t = *t + 1
return fmt.Sprintf("127.0.0.1:%d", *t)
}
func (t *tcp) retries() int {
return 500
}
type unix string
func (u *unix) addr() string {
name := randstr(8)
if *u != "" {
name = filepath.FromSlash(path.Join(string(*u), name))
}
return name
}
func (u *unix) retries() int {
return 4
}
//
func (r *rpcServer) run() error {
var conn connection
var err error
var listener net.Listener
r.running = true //设置默认运行状态为true
h := meta(r.conf.prefix)//设置自定数据类型 参数值为config 的前缀
h.output("objects", strings.Join(r.objs, ", "))//方法参数 key 为常量 objects 参数 val 值为注册服务对象元素名称 。使用,链接的字符串
//协议判断
switch r.conf.proto {
case "tcp":
conn = new(tcp)
default:
r.conf.proto = "unix"
conn = new(unix)
}
//获取尝试连接500次 但是只要有一次执行成功 立刻返回
for i := 0; i < conn.retries(); i++ {
r.conf.addr = conn.addr()
listener, err = net.Listen(r.conf.proto, r.conf.addr)
if err == nil {
break
}
}
if err != nil {
h.output("fatal", fmt.Sprintf("%s: Could not connect in %d attemps, using %s protocol", errorCodeConnFailed, conn.retries(), r.conf.proto))
return err
}
h.output("auth-token", defaultServer.secret)
h.output("ready", fmt.Sprintf("proto=%s addr=%s", r.conf.proto, r.conf.addr))
for {
var conn net.Conn
conn, err = listener.Accept()
if err != nil {
h.output("fatal", fmt.Sprintf("err-http-serve: %s", err.Error()))
continue
}
go r.serveConn(conn, h)
}
}
server.go 源码阅读的更多相关文章
- 【原】AFNetworking源码阅读(一)
[原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...
- Android源码阅读 – Zygote
@Dlive 本文档: 使用的Android源码版本为:Android-4.4.3_r1 kitkat (源码下载: http://source.android.com/source/index.ht ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- CI框架源码阅读笔记1 - 环境准备、基本术语和框架流程
最开始使用CI框架的时候,就打算写一个CI源码阅读的笔记系列,可惜虎头蛇尾,一直没有行动.最近项目少,总算是有了一些时间去写一些东西.于是准备将之前的一些笔记和经验记录下来,一方面权作备忘,另一方面时 ...
- 转-OpenJDK源码阅读导航跟编译
OpenJDK源码阅读导航 OpenJDK源码阅读导航 博客分类: Virtual Machine HotSpot VM Java OpenJDK openjdk 这是链接帖.主体内容都在各链接中. ...
- Netty源码阅读(一) ServerBootstrap启动
Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...
- Spark源码阅读之存储体系--存储体系概述与shuffle服务
一.概述 根据<深入理解Spark:核心思想与源码分析>一书,结合最新的spark源代码master分支进行源码阅读,对新版本的代码加上自己的一些理解,如有错误,希望指出. 1.块管理器B ...
- Rpc框架dubbo-client(v2.6.3) 源码阅读(二)
接上一篇 dubbo-server 之后,再来看一下 dubbo-client 是如何工作的. dubbo提供者服务示例, 其结构是这样的!dubbo://192.168.11.6:20880/com ...
- InfluxDB源码阅读之snapshotter服务
操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 服务模块介绍 源码路径: github.com/influxda ...
随机推荐
- Java不走弯路教程(6.JDBC)
6.JDBC 在上一章,我们完成了MyDb数据库的简单的客户段调用.作为产品我们还封装了驱动程序,并且提供了统一的调用接口. 大家应该知道,市面上有多种数据库产品,比如Oracle,Mysql,DB2 ...
- Ng1从1.3开始的变更史
从今有个ng1 spa项目,项目可能会有ng1的版本升级问题,特简要摘录从1.3的主要版本变更,所以内容来自migration guide. 1.3的主要变更: 1.controller不能再以全局简 ...
- php coding中的一些小问题
最近在SAE上写微博应用,碰到一些小问题,记下来,以供参考: 1.出错提示: Fatal error: Can't use function return value in write context ...
- Jmeter(二十六)_数据驱动测试
花了一点时间做了一个通用的执行引擎,好处就是我不用再关注测试脚本的内容,而是用测试用例的数据去驱动我们执行的方向.(这个只适合单个接口的测试,具体运用到接口自动化时,还是要靠手动去编写脚本!) 首先我 ...
- 给你的网页添加一个随机的BGM
大晚上的,突然想到,我这么喜欢听歌的人,博客里怎么能少了BGM呢,说干就干. 首先,给博客侧边栏加一个空div:<div id="music"></div> ...
- 基于NetMQ的TLS框架NetMQ.Security的实现分析
基于NetMQ的TLS框架NetMQ.Security的实现分析 前言 介绍 交互过程 支持的协议 TLS协议 支持的算法 实现 握手 第一次握手 Client Hello 第二次握手 Server ...
- removeElement
Description: Given an array and a value, remove all instances of that value in place and return the ...
- 微信小程序之获取用户位置权限(拒绝后提醒)
微信小程序获取用户当前位置有三个方式: 1. wx.getLocation(多与wx.openLocation一起用) 获取当前的精度.纬度.速度.不需要授权.当type设置为gcj02 返回可用于w ...
- Windows10远程报错:由于CredSSP加密Oracle修正
Windows10远程桌面连接 报错信息 : 网上找到方法 但是奈何是 "Win10家庭版" 不能使用这个办法,具体操作可以看最后的引用链接 !!!! 策略路径:"计算机 ...
- 转载 Elasticsearch开发环境搭建(Eclipse\MyEclipse + Maven)
概要: 1.使用Eclipse搭建Elasticsearch详情参考下面链接 2.Java Elasticsearch 配置 3.ElasticSearch Java Api(一) -添加数据创建索引 ...