当前位置: 首页>>代码示例>>Golang>>正文


Golang ResponseWriter.RemoteAddr方法代码示例

本文整理汇总了Golang中github.com/miekg/dns.ResponseWriter.RemoteAddr方法的典型用法代码示例。如果您正苦于以下问题:Golang ResponseWriter.RemoteAddr方法的具体用法?Golang ResponseWriter.RemoteAddr怎么用?Golang ResponseWriter.RemoteAddr使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在github.com/miekg/dns.ResponseWriter的用法示例。

在下文中一共展示了ResponseWriter.RemoteAddr方法的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。

示例1: handleQuery

// handleQUery is used to handle DNS queries in the configured domain
func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
	q := req.Question[0]
	defer func(s time.Time) {
		d.logger.Printf("[DEBUG] dns: request for %v (%v)", q, time.Now().Sub(s))
	}(time.Now())

	// Switch to TCP if the client is
	network := "udp"
	if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok {
		network = "tcp"
	}

	// Setup the message response
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = (len(d.recursors) > 0)

	// Only add the SOA if requested
	if req.Question[0].Qtype == dns.TypeSOA {
		d.addSOA(d.domain, m)
	}

	// Dispatch the correct handler
	d.dispatch(network, req, m)

	// Write out the complete response
	if err := resp.WriteMsg(m); err != nil {
		d.logger.Printf("[WARN] dns: failed to respond: %v", err)
	}
}
开发者ID:zendesk,项目名称:consul,代码行数:32,代码来源:dns.go


示例2: handlePtr

// handlePtr is used to handle "reverse" DNS queries
func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
	q := req.Question[0]
	defer func(s time.Time) {
		d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)",
			q, time.Now().Sub(s), resp.RemoteAddr().String(),
			resp.RemoteAddr().Network())
	}(time.Now())

	// Setup the message response
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = (len(d.recursors) > 0)

	// Only add the SOA if requested
	if req.Question[0].Qtype == dns.TypeSOA {
		d.addSOA(d.domain, m)
	}

	datacenter := d.agent.config.Datacenter

	// Get the QName without the domain suffix
	qName := strings.ToLower(dns.Fqdn(req.Question[0].Name))

	args := structs.DCSpecificRequest{
		Datacenter: datacenter,
		QueryOptions: structs.QueryOptions{
			Token:      d.agent.config.ACLToken,
			AllowStale: d.config.AllowStale,
		},
	}
	var out structs.IndexedNodes

	// TODO: Replace ListNodes with an internal RPC that can do the filter
	// server side to avoid transferring the entire node list.
	if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil {
		for _, n := range out.Nodes {
			arpa, _ := dns.ReverseAddr(n.Address)
			if arpa == qName {
				ptr := &dns.PTR{
					Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0},
					Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain),
				}
				m.Answer = append(m.Answer, ptr)
				break
			}
		}
	}

	// nothing found locally, recurse
	if len(m.Answer) == 0 {
		d.handleRecurse(resp, req)
		return
	}

	// Write out the complete response
	if err := resp.WriteMsg(m); err != nil {
		d.logger.Printf("[WARN] dns: failed to respond: %v", err)
	}
}
开发者ID:nathanielc,项目名称:consul,代码行数:61,代码来源:dns.go


示例3: ServeDNS

// ServeDNS resolution.
func (h *RandomUpstream) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	ns := h.upstream[rand.Intn(len(h.upstream))]
	ns = defaultPort(ns)

	for _, q := range r.Question {
		log.Printf("[info] [%v] <== %s %s %v (ns %s)\n", r.Id,
			dns.ClassToString[q.Qclass],
			dns.TypeToString[q.Qtype],
			q.Name,
			ns)
	}

	client := &dns.Client{
		Net: w.RemoteAddr().Network(),
	}

	res, rtt, err := client.Exchange(r, ns)
	if err != nil {
		msg := new(dns.Msg)
		msg.SetRcode(r, dns.RcodeServerFailure)
		w.WriteMsg(msg)
		return
	}

	log.Printf("[info] [%v] ==> %s:", r.Id, rtt)
	for _, a := range res.Answer {
		log.Printf("[info] [%v] ----> %s\n", r.Id, a)
	}

	err = w.WriteMsg(res)
	if err != nil {
		log.Printf("[error] [%v] failed to respond – %s", r.Id, err)
	}
}
开发者ID:bitland,项目名称:sdns,代码行数:35,代码来源:upstream.go


示例4: redirectQuery

func (self *TrivialDnsServer) redirectQuery(w dns.ResponseWriter, r *dns.Msg, newName string) {
	self.Count("redirected_requests")
	if !strings.HasSuffix(newName, ".") {
		newName = newName + "."
	}

	newR := new(dns.Msg)
	newR.SetQuestion(dns.Fqdn(newName), dns.TypeA)

	if response, _, err := self.exchangeWithUpstream(newR); err == nil {
		ip := self.getSingleSimpleAnswer(response)
		if ip == nil {
			debug("%s redirect to %s yielded no answer", w.RemoteAddr(), newName)
			self.Count("redirected_nowhere")
			self.refuse(w, r)
			return
		}
		self.Count("redirected_successively")
		self.respondSuccessively(w, r, *ip)
	} else {
		self.Count("upstream_errors")
		self.refuse(w, r)
		log.Printf("%s: error: %s", w.RemoteAddr(), err)
	}
}
开发者ID:e-max,项目名称:trivialdns,代码行数:25,代码来源:trivialdns.go


示例5: ServeDNS

func (h ENUMHandler) ServeDNS(writer dns.ResponseWriter, request *dns.Msg) {

	defer func(s time.Time) {
		h.Trace.Printf("dns request for %v (%s) (%v) from client %s (%s)",
			request.Question[0], "udp", time.Now().Sub(s), writer.RemoteAddr().String(),
			writer.RemoteAddr().Network())
	}(time.Now())

	if answer, err := h.createAnswer(request); err == nil {

		if answer == nil {
			h.Trace.Printf("no result found for %s", request.Question[0])
			notfound := &dns.Msg{}
			notfound.SetReply(request)
			notfound.SetRcode(request, dns.RcodeSuccess)
			writer.WriteMsg(notfound)
			return
		}

		if err := writer.WriteMsg(answer); err != nil {
			h.Error.Printf("error sending answer: %v", err)
		}

	} else {
		h.Error.Printf("[ERR] Error getting the answer: %v", err)
		error := &dns.Msg{}
		error.SetReply(request)
		error.SetRcode(request, dns.RcodeServerFailure)
		writer.WriteMsg(error)
	}

}
开发者ID:hadrienk,项目名称:enum-dns,代码行数:32,代码来源:dns.go


示例6:

func ( p Proxy ) ServeDNS (w dns.ResponseWriter, r *dns.Msg) {
    c := dns.NewClient ()

    c.Net = PROTO
    if TCP_REGEX != nil {
        for _, q := range r.Question {
            if TCP_REGEX.MatchString (q.Name) {
                LOG.Printf ("Tcp proto regex match: %s", q.Name)
                c.Net = "tcp"
                break
            }
        }
    }

    c.ReadTimeout = TIMEOUT
    c.WriteTimeout = TIMEOUT

    if rs, err := c.Exchange (r, p.Server()); err == nil {
        if DEBUG {
            LOG.Printf ("DEBUG %s\n%v", w.RemoteAddr(), rs)
        }
        w.Write (rs)
    } else {
        dns.Refused (w, r)
        LOG.Printf ("%s %s", w.RemoteAddr(), err)
    }
}
开发者ID:zincxenon,项目名称:CodeTest,代码行数:27,代码来源:gfc.go


示例7: proxy

func proxy(addr string, w dns.ResponseWriter, req *dns.Msg) {
	transport := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		transport = "tcp"
	}
	if isTransfer(req) {
		if transport != "tcp" {
			dns.HandleFailed(w, req)
			return
		}
		t := new(dns.Transfer)
		c, err := t.In(req, addr)
		if err != nil {
			dns.HandleFailed(w, req)
			return
		}
		if err = t.Out(w, req, c); err != nil {
			dns.HandleFailed(w, req)
			return
		}
		return
	}
	c := &dns.Client{Net: transport}
	resp, _, err := c.Exchange(req, addr)
	if err != nil {
		dns.HandleFailed(w, req)
		return
	}
	w.WriteMsg(resp)
}
开发者ID:40a,项目名称:dns-reverse-proxy,代码行数:30,代码来源:dns_reverse_proxy.go


示例8: handleRecurse

// handleRecurse is used to handle recursive DNS queries
func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) {
	q := req.Question[0]
	network := "udp"
	defer func(s time.Time) {
		d.logger.Printf("[DEBUG] dns: request for %v (%s) (%v)", q, network, time.Now().Sub(s))
	}(time.Now())

	// Switch to TCP if the client is
	if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok {
		network = "tcp"
	}

	// Recursively resolve
	c := &dns.Client{Net: network}
	r, rtt, err := c.Exchange(req, d.recursor)

	// On failure, return a SERVFAIL message
	if err != nil {
		d.logger.Printf("[ERR] dns: recurse failed: %v", err)
		m := &dns.Msg{}
		m.SetReply(req)
		m.RecursionAvailable = true
		m.SetRcode(req, dns.RcodeServerFailure)
		resp.WriteMsg(m)
		return
	}
	d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v)", q, rtt)

	// Forward the response
	if err := resp.WriteMsg(r); err != nil {
		d.logger.Printf("[WARN] dns: failed to respond: %v", err)
	}
}
开发者ID:kawaken,项目名称:consul,代码行数:34,代码来源:dns.go


示例9: handleDNSExternal

func (s *DNS) handleDNSExternal(w dns.ResponseWriter, req *dns.Msg) {

	network := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		network = "tcp"
	}

	c := &dns.Client{Net: network}
	var r *dns.Msg
	var err error
	for _, recursor := range s.recursors {

		if recursor == "" {
			log.Printf("Found empty recursor")
			continue
		}

		log.Printf("Forwarding request to external recursor for: %s", req.Question[0].Name)

		r, _, err = c.Exchange(req, recursor)
		if err == nil {
			if err := w.WriteMsg(r); err != nil {
				log.Printf("DNS lookup failed %v", err)
			}
			return
		}
	}

	dns.HandleFailed(w, req)
}
开发者ID:faisyl,项目名称:docker-spy,代码行数:30,代码来源:dns.go


示例10: getServerReply

// Forwards a DNS request to the specified nameservers. On success, the
// original reply packet will be returned to the caller. On failure, a
// new packet will be returned with `RCODE` set to `SERVFAIL`.
// Even though the original `ResponseWriter` object is taken as an argument,
// this function does not send a reply to the client. Instead, the
// packet is returned for further processing by the caller.
func getServerReply(w dns.ResponseWriter, req *dns.Msg) *dns.Msg {
	if *verbose {
		log.Print("Forwarding ", req.Question[0].Name, "/", dns.Type(req.Question[0].Qtype).String())
	}

	// create a new DNS client

	client := &dns.Client{Net: "udp", ReadTimeout: 4 * time.Second, WriteTimeout: 4 * time.Second, SingleInflight: true}

	if _, tcp := w.RemoteAddr().(*net.TCPAddr); tcp {
		client.Net = "tcp"
	}

	var r *dns.Msg
	var err error

	// loop through the specified nameservers and forward them the request

	// the request ID is used as a starting point in order to introduce at least
	// some element of randomness, instead of always hitting the first nameserver

	for i := 0; i < len(nameservers); i++ {
		r, _, err = client.Exchange(req, nameservers[(int(req.Id)+i)%len(nameservers)])

		if err == nil {
			r.Compress = true

			return r
		}
	}

	log.Print("Failed to forward request.", err)
	return getEmptyMsg(w, req, dns.RcodeServerFailure)
}
开发者ID:RoliSoft,项目名称:Split-Tunnel-Host,代码行数:40,代码来源:dnsserv.go


示例11: handle

func (h *Handler) handle(proto string, w dns.ResponseWriter, r *dns.Msg) {
	ques := question.NewQuestion(r.Question[0])

	subnet := ""
	if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok {
		subnet = networks.Find(ip.IP)
	}
	if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		subnet = networks.Find(ip.IP)
	}

	if subnet == "" {
		dns.HandleFailed(w, r)
		return
	}

	if ques.IsIpQuery && ques.TopDomain == "vpn" {
		msg, err := h.reslvr.LookupUser(proto, ques, subnet, r)
		if err != nil {
			dns.HandleFailed(w, r)
			return
		}
		w.WriteMsg(msg)
	} else {
		servers := database.DnsServers[subnet]
		res, err := h.reslvr.Lookup(proto, servers, r)
		if err != nil {
			dns.HandleFailed(w, r)
			return
		}

		w.WriteMsg(res)
	}
}
开发者ID:carriercomm,项目名称:pritunl-dns,代码行数:34,代码来源:handler.go


示例12: Proto

// Proto gets the protocol used as the transport. This will be udp or tcp.
func Proto(w dns.ResponseWriter) string {
	if _, ok := w.RemoteAddr().(*net.UDPAddr); ok {
		return "udp"
	}
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		return "tcp"
	}
	return "udp"
}
开发者ID:yuewko,项目名称:coredns,代码行数:10,代码来源:state.go


示例13: handleRequest

func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
	kv := llog.KV{}
	// Can be nil during testing
	if raddr := w.RemoteAddr(); raddr != nil {
		kv["srcAddr"] = raddr.String()
	}

	if err := validateRequest(r); err != nil {
		kv["err"] = err
		llog.Warn("invalid request", kv)
		sendFormatError(w, r)
		return
	}

	start := time.Now()
	kv["question"] = r.Question[0].Name
	kv["questionType"] = r.Question[0].Qtype
	llog.Info("handling request", kv)

	rr := NewReq{r, make(chan *dns.Msg)}
	newCh <- rr
	m := <-rr.ReplyCh

	kv["ms"] = int64(time.Since(start).Nanoseconds() / 1e6)

	if m == nil {
		llog.Warn("error handling request", kv)
		dns.HandleFailed(w, r)
		return
	}

	//we need to make sure the sent ID matches the replied one
	//it might be different if we combined in-flight messages
	//copy the struct so we don't affect anything else handling this
	m2 := *m
	m2.Id = r.Id
	m = &m2

	//we always want to compress since there's no downsides afaik
	m.Compress = true

	kv["rcode"], _ = dns.RcodeToString[m.Rcode]
	if len(m.Answer) > 0 {
		kv["answer"] = m.Answer[0]
		kv["answerCnt"] = len(m.Answer)
	}
	kv["len"] = m.Len()
	llog.Info("responding to request", kv)

	err := w.WriteMsg(m)
	if err != nil {
		kv["err"] = err
		llog.Warn("error writing response", kv)
		//no need to handle HandleFailed here because we cannot write
	}
}
开发者ID:levenlabs,项目名称:struggledns,代码行数:56,代码来源:main.go


示例14: ServeDNS

func (ds *DNSServer) ServeDNS(rw dns.ResponseWriter, mes *dns.Msg) {
	resp := new(dns.Msg)

	for _, q := range mes.Question {
		log.Printf("DNS request from %s: %s", rw.RemoteAddr(), &q)
		switch q.Qtype {
		case dns.TypeA, dns.TypeAAAA:
			val, err := ds.HandleLookup(q.Name)
			if err != nil {
				log.Println(err)
				continue
			}

			if q.Qclass != dns.ClassINET {
				log.Printf("error: got invalid DNS question class %d\n", q.Qclass)
				continue
			}

			header := dns.RR_Header{
				Name:   q.Name,
				Rrtype: q.Qtype,
				Class:  dns.ClassINET,
				Ttl:    DefaultResponseTTL,
			}

			var rr dns.RR
			// not really super sure why these have to be different types
			if q.Qtype == dns.TypeA {
				rr = &dns.A{
					A:   net.ParseIP(val),
					Hdr: header,
				}
			} else if q.Qtype == dns.TypeAAAA {
				rr = &dns.AAAA{
					AAAA: net.ParseIP(val),
					Hdr:  header,
				}
			} else {
				panic("unreachable")
			}

			resp.Answer = append(resp.Answer, rr)

		default:
			log.Printf("unhandled qtype: %d\n", q.Qtype)
		}
	}

	resp.Authoritative = true
	resp.Id = mes.Id
	resp.Response = true

	if err := rw.WriteMsg(resp); err != nil {
		log.Printf("error responding to DNS query: %s", err)
	}
}
开发者ID:pombredanne,项目名称:camlistore,代码行数:56,代码来源:camnetdns.go


示例15: HandleNonMesos

// HandleNonMesos handles non-mesos queries by forwarding to configured
// external DNS servers.
func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) {
	logging.CurLog.NonMesosRequests.Inc()
	m, err := res.fwd(r, w.RemoteAddr().Network())
	if err != nil {
		m = new(dns.Msg).SetRcode(r, rcode(err))
	} else if len(m.Answer) == 0 {
		logging.CurLog.NonMesosNXDomain.Inc()
	}
	reply(w, m)
}
开发者ID:alberts,项目名称:mesos-dns,代码行数:12,代码来源:resolver.go


示例16: sendTruncated

func sendTruncated(w dns.ResponseWriter, msgHdr dns.MsgHdr) {
	emptyResp := new(dns.Msg)
	emptyResp.MsgHdr = msgHdr
	emptyResp.Response = true
	if _, isTCP := w.RemoteAddr().(*net.TCPAddr); isTCP {
		dns.HandleFailed(w, emptyResp)
		return
	}
	emptyResp.Truncated = true
	w.WriteMsg(emptyResp)
}
开发者ID:jedisct1,项目名称:rpdns,代码行数:11,代码来源:rpdns.go


示例17: debug_request

func debug_request(request dns.Msg, question dns.Question, writer dns.ResponseWriter) string {
	addr := writer.RemoteAddr().String() // ipaddr string
	s := []string{}
	// TODO: put tcp/udp in here
	s = append(s, fmt.Sprintf("Received request from %s ", addr))
	s = append(s, fmt.Sprintf("for %s ", question.Name))
	s = append(s, fmt.Sprintf("opcode: %d ", request.Opcode))
	s = append(s, fmt.Sprintf("rrtype: %d ", question.Qtype))
	s = append(s, fmt.Sprintf("rrclass: %d ", question.Qclass))
	return strings.Join(s, "")
}
开发者ID:rackerlabs,项目名称:slappy,代码行数:11,代码来源:slapdns.go


示例18: HandleForwarding

// HandleForwarding forwards a request to the nameservers and returns the response
func (s *Server) HandleForwarding(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) {
	defer trace.End(trace.Begin(r.String()))

	var m *mdns.Msg
	var err error
	var try int

	if len(s.Nameservers) == 0 {
		log.Errorf("No nameservers defined, can not forward")
		return false, respServerFailure(w, r)
	}

	// which protocol are they talking
	tcp := false
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		tcp = true
	}

	// Use request ID for "random" nameserver selection.
	nsid := int(r.Id) % len(s.Nameservers)

Redo:
	nameserver := s.Nameservers[nsid]
	if i := strings.Index(nameserver, ":"); i < 0 {
		nameserver += ":53"
	}

	if tcp {
		m, _, err = s.tcpclient.Exchange(r, nameserver)
	} else {
		m, _, err = s.udpclient.Exchange(r, nameserver)
	}
	if err != nil {
		// Seen an error, this can only mean, "server not reached", try again but only if we have not exausted our nameservers.
		if try < len(s.Nameservers) {
			try++
			nsid = (nsid + 1) % len(s.Nameservers)
			goto Redo
		}

		log.Errorf("Failure to forward request: %q", err)
		return false, respServerFailure(w, r)
	}

	// We have a response so cache it
	s.cache.Add(m)

	m.Compress = true
	if err := w.WriteMsg(m); err != nil {
		log.Errorf("Error writing response: %q", err)
		return true, err
	}
	return true, nil
}
开发者ID:kjplatz,项目名称:vic,代码行数:55,代码来源:dns.go


示例19: allowed

func allowed(w dns.ResponseWriter, req *dns.Msg) bool {
	if !isTransfer(req) {
		return true
	}
	remote := extractHost(w.RemoteAddr().String())
	for _, ip := range transferIPs {
		if ip == remote {
			return true
		}
	}
	return false
}
开发者ID:40a,项目名称:dns-reverse-proxy,代码行数:12,代码来源:dns_reverse_proxy.go


示例20: zoneHandler

func (z *zone) zoneHandler(c *config, w dns.ResponseWriter, req *dns.Msg) {
	c.stats.Incr("query.request", 1)
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.Answer = []dns.RR{}
	questions := []string{}
	answers := []string{}
	if len(req.Question) != 1 {
		c.stats.Incr("query.error", 1)
		log.Printf("Warning: len(req.Question) != 1")
		return
	}
	q := req.Question[0]
	questions = append(questions, fmt.Sprintf("%s[%s]", q.Name, dns.TypeToString[q.Qtype]))
	if q.Qclass != uint16(dns.ClassINET) {
		c.stats.Incr("query.error", 1)
		log.Printf("Warning: skipping unhandled class: %s", dns.ClassToString[q.Qclass])
		return
	}
	for _, record := range z.rrs {
		h := record.Header()
		if q.Name != h.Name {
			continue
		}
		txt := record.String()
		if q.Qtype == dns.TypeA && h.Rrtype == dns.TypeCNAME { // special handling for A queries w/CNAME results
			if q.Name == dns.Fqdn(z.name) { // flatten root CNAME
				flat, err := c.flattenCNAME(record.(*dns.CNAME))
				if err != nil || flat == nil {
					log.Printf("flattenCNAME error: %s", err.Error())
				} else {
					for _, record := range flat {
						m.Answer = append(m.Answer, record)
						answers = append(answers, "(FLAT)"+record.String())
					}
				}
				continue
			} // don't flatten other CNAMEs for now
		} else if q.Qtype != h.Rrtype && q.Qtype != dns.TypeANY { // skip RRs that don't match
			continue
		}
		m.Answer = append(m.Answer, record)
		answers = append(answers, txt)
	}
	//m.Extra = []dns.RR{}
	//m.Extra = append(m.Extra, &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"DNS rocks"}})
	c.debug(fmt.Sprintf("Query [%s] %s -> %s ", w.RemoteAddr().String(), strings.Join(questions, ","), strings.Join(answers, ",")))
	c.stats.Incr("query.answer", 1)

	w.WriteMsg(m)
}
开发者ID:nmcclain,项目名称:neddns,代码行数:52,代码来源:neddns.go



注:本文中的github.com/miekg/dns.ResponseWriter.RemoteAddr方法示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。