扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
应用于搭建 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。
在殷都等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站设计制作、网站设计 网站设计制作定制设计,公司网站建设,企业网站建设,品牌网站设计,营销型网站,成都外贸网站建设,殷都网站建设费用合理。
Go 是谷歌的编程语言,而不是社区的。在这位博主看来,虽然 Go 语言拥有一个贡献者社区,但是它并不是社区的项目,只是谷歌的一个项目。所以只要是谷歌反对的东西,没有人可以把这个东西加到 Go 语言中。
InfoQ 记者也第一时间联系了《Go 并发编程实战》作者、前轻松筹大数据负责人郝林,他的观点是:Go 语言是大家的,只有伪爱好者才会谈舍弃。在郝林看来,Go 语言官方团队在谷歌内部实属一个很小的团队,但其成员几乎个个都是技术大神。
很多社区成员为 Go 语言贡献了很多重要并且有价值的东西,这些从贡献者和提交者的多样性就可以看出来。但谷歌作为整个 Go 社区的守门人,它独自决定什么东西可以被 Go 语言接受,什么不能被接受。
在 Go 语言模块系统上发生的一件事情,谷歌 Go 语言核心团队的一名成员放弃了由外部 Go 社区开发的一个模块系统,因为它使用了另一种不同的模型。Go 语言拥有一个贡献者社区,但是它并不是一个社区项目。
package p2p
import (
"context"
"errors"
"time"
net "gx/ipfs/QmPjvxTpVH8qJyQDnxnsxF9kv9jezKD1kozz1hs3fCGsNh/go-libp2p-net"
manet "gx/ipfs/QmV6FjemM1K8oXjrvuq3wuVWWoU2TLDPmNnKrxHzY3v6Ai/go-multiaddr-net"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
pro "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
pstore "gx/ipfs/QmZR2XWVVBCtbgBWnQhWk2xcQfaR3W8faQPriAiaaj7rsr/go-libp2p-peerstore"
p2phost "gx/ipfs/Qmb8T6YBBsjYsVGfrihQLfCJveczZnneSBqBKkYEBWDjge/go-libp2p-host"
peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer"
)
//P2P结构保存当前正在运行的流/监听器的信息
// P2P structure holds information on currently running streams/listeners
type P2P struct {
//监听器
Listeners ListenerRegistry
//数据流
Streams StreamRegistry
//节点ID
identity peer.ID
//节点地址
peerHost p2phost.Host
//一个线程安全的对等节点存储
peerstore pstore.Peerstore
}
//创建一个新的p2p结构
// NewP2P creates new P2P struct
//这个新的p2p结构不包含p2p结构中的监听器和数据流
func NewP2P(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore) *P2P {
return P2P{
identity: identity,
peerHost: peerHost,
peerstore: peerstore,
}
}
//新建一个数据流 工具方法 构建一个有节点id,内容和协议的流
func (p2p P2P) newStreamTo(ctx2 context.Context, p peer.ID, protocol string) (net.Stream, error) {
//30s 后会自动timeout
ctx, cancel := context.WithTimeout(ctx2, time.Second 30) //TODO: configurable?
defer cancel()
err := p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: p})
if err != nil {
return nil, err
}
return p2p.peerHost.NewStream(ctx2, p, pro.ID(protocol))
}
//对话为远程监听器创建新的P2P流
//创建一个新的p2p流实现对对话的监听
// Dial creates new P2P stream to a remote listener
//Multiaddr是一种跨协议、跨平台的表示格式的互联网地址。它强调明确性和自我描述。
//对内接收
func (p2p P2P) Dial(ctx context.Context, addr ma.Multiaddr, peer peer.ID, proto string, bindAddr ma.Multiaddr) ( ListenerInfo, error) {
//获取一些节点信息 network, host, nil
lnet, _, err := manet.DialArgs(bindAddr)
if err != nil {
return nil, err
}
//监听信息
listenerInfo := ListenerInfo{
//节点身份
Identity: p2p.identity,
////应用程序协议标识符。
Protocol: proto,
}
//调用newStreamTo 通过ctx(内容) peer(节点id) proto(协议标识符) 参数获取一个新的数据流
remote, err := p2p.newStreamTo(ctx, peer, proto)
if err != nil {
return nil, err
}
//network协议标识
switch lnet {
//network为"tcp", "tcp4", "tcp6"
case "tcp", "tcp4", "tcp6":
//从监听器获取新的信息 nla.Listener, nil
listener, err := manet.Listen(bindAddr)
if err != nil {
if err2 := remote.Reset(); err2 != nil {
return nil, err2
}
return nil, err
}
//将获取的新信息保存到listenerInfo
listenerInfo.Address = listener.Multiaddr()
listenerInfo.Closer = listener
listenerInfo.Running = true
//开启接受
go p2p.doAccept(listenerInfo, remote, listener)
default:
return nil, errors.New("unsupported protocol: " + lnet)
}
return listenerInfo, nil
}
//
func (p2p *P2P) doAccept(listenerInfo *ListenerInfo, remote net.Stream, listener manet.Listener) {
//关闭侦听器并删除流处理程序
defer listener.Close()
//Returns a Multiaddr friendly Conn
//一个有好的 Multiaddr 连接
local, err := listener.Accept()
if err != nil {
return
}
stream := StreamInfo{
//连接协议
Protocol: listenerInfo.Protocol,
//定位节点
LocalPeer: listenerInfo.Identity,
//定位节点地址
LocalAddr: listenerInfo.Address,
//远程节点
RemotePeer: remote.Conn().RemotePeer(),
//远程节点地址
RemoteAddr: remote.Conn().RemoteMultiaddr(),
//定位
Local: local,
//远程
Remote: remote,
//注册码
Registry: p2p.Streams,
}
//注册连接信息
p2p.Streams.Register(stream)
//开启节点广播
stream.startStreaming()
}
//侦听器将流处理程序包装到侦听器中
// Listener wraps stream handler into a listener
type Listener interface {
Accept() (net.Stream, error)
Close() error
}
//P2PListener保存关于侦听器的信息
// P2PListener holds information on a listener
type P2PListener struct {
peerHost p2phost.Host
conCh chan net.Stream
proto pro.ID
ctx context.Context
cancel func()
}
//等待侦听器的连接
// Accept waits for a connection from the listener
func (il *P2PListener) Accept() (net.Stream, error) {
select {
case c := -il.conCh:
return c, nil
case -il.ctx.Done():
return nil, il.ctx.Err()
}
}
//关闭侦听器并删除流处理程序
// Close closes the listener and removes stream handler
func (il *P2PListener) Close() error {
il.cancel()
il.peerHost.RemoveStreamHandler(il.proto)
return nil
}
// Listen创建新的P2PListener
// Listen creates new P2PListener
func (p2p P2P) registerStreamHandler(ctx2 context.Context, protocol string) ( P2PListener, error) {
ctx, cancel := context.WithCancel(ctx2)
list := P2PListener{
peerHost: p2p.peerHost,
proto: pro.ID(protocol),
conCh: make(chan net.Stream),
ctx: ctx,
cancel: cancel,
}
p2p.peerHost.SetStreamHandler(list.proto, func(s net.Stream) {
select {
case list.conCh - s:
case -ctx.Done():
s.Reset()
}
})
return list, nil
}
// NewListener创建新的p2p侦听器
// NewListener creates new p2p listener
//对外广播
func (p2p P2P) NewListener(ctx context.Context, proto string, addr ma.Multiaddr) ( ListenerInfo, error) {
//调用registerStreamHandler 构造一个新的listener
listener, err := p2p.registerStreamHandler(ctx, proto)
if err != nil {
return nil, err
}
//构造新的listenerInfo
listenerInfo := ListenerInfo{
Identity: p2p.identity,
Protocol: proto,
Address: addr,
Closer: listener,
Running: true,
Registry: p2p.Listeners,
}
go p2p.acceptStreams(listenerInfo, listener)
//注册连接信息
p2p.Listeners.Register(listenerInfo)
return listenerInfo, nil
}
//接受流
func (p2p *P2P) acceptStreams(listenerInfo *ListenerInfo, listener Listener) {
for listenerInfo.Running {
//一个有好的 远程 连接
remote, err := listener.Accept()
if err != nil {
listener.Close()
break
}
}
//取消注册表中的p2p侦听器
p2p.Listeners.Deregister(listenerInfo.Protocol)
}
// CheckProtoExists检查是否注册了协议处理程序
// mux处理程序
// CheckProtoExists checks whether a protocol handler is registered to
// mux handler
func (p2p *P2P) CheckProtoExists(proto string) bool {
protos := p2p.peerHost.Mux().Protocols()
for _, p := range protos {
if p != proto {
continue
}
return true
}
return false
}
1、上传服务为:go语言搭建的单独文件服务器地址
2、现象:
3、解决方法
1、解压压缩包到go工作目录,如解压到E:\opensource\go\go,解压后的目录结构如下:E:\opensource\go\go├─api├─bin│├─go.exe│├─godoc.exe│└─gofmt.exe├─doc├─include├─lib├─misc├─pkg├─src└─test2、增加环境变量GOROOT,取值为上面的go工作目录3、Path环境变量中添加";%GOROOT%\bin",以便能够直接调用go命令来编译go代码,至此go编译环境就配置好了注:如果不想手动设置系统环境变量,也可下载go启动环境批处理附件,修改goenv.bat文件中的GOROOT值为上面的go工作目录后直接双击该bat文件,go编译环境变量即设置完成。4、测试go编译环境,启动一个cmd窗口,直接输入go,看到下面的提示就是搭建成功了E:\opensource\go\gogoGoisatoolformanagingGosourcecode.Usage:gocommand[arguments]Thecommandsare:buildcompilepackagesanddependenciescleanremoveobjectfilesdocrungodoconpackagesourcesenvprintGoenvironmentinformationfixrungotoolfixonpackagesfmtrungofmtonpackagesourcesgetdownloadandinstallpackagesanddependenciesinstallcompileandinstallpackagesanddependencieslistlistpackagesruncompileandrunGoprogramtesttestpackagestoolrunspecifiedgotoolversionprintGoversionvetrungotoolvetonpackagesUse"gohelp[command]"formoreinformationaboutacommand.Additionalhelptopics:gopathGOPATHenvironmentvariablepackagesdescriptionofpackagelistsremoteremoteimportpathsyntaxtestflagdescriptionoftestingflagstestfuncdescriptionoftestingfunctionsUse"gohelp[topic]"formoreinformationaboutthattopic.5、编译helloworld测试程序,go语言包中test目录带有helloworld.go测试程序,源码见"附一helloworld.go",直接调用"gobuildhelloworld.go"就生成了"helloworld.exe"可执行程序,运行一下这个程序看到了我们期望的hello,wolrd。E:\opensource\go\go\testgobuildhelloworld.goE:\opensource\go\go\testhelloworld.exehello,worldE:\opensource\go\go\test附一helloworld.go//cmpout//Copyright2009TheGoAuthors.Allrightsreserved.//UseofthissourcecodeisgovernedbyaBSD-style//licensethatcanbefoundintheLICENSEfile.//Testthatwecandopage1oftheCbook.packagemainfuncmain(){print("hello,world\n")}
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流