github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/message.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:44</date> 10 //</624342658466189312> 11 12 13 package p2p 14 15 import ( 16 "bytes" 17 "errors" 18 "fmt" 19 "io" 20 "io/ioutil" 21 "sync/atomic" 22 "time" 23 24 "github.com/ethereum/go-ethereum/event" 25 "github.com/ethereum/go-ethereum/p2p/discover" 26 "github.com/ethereum/go-ethereum/rlp" 27 ) 28 29 //msg定义p2p消息的结构。 30 // 31 //注意,由于有效负载读卡器 32 //发送时消耗。无法创建消息和 33 //发送任意次数。如果要重用编码的 34 //结构,将有效负载编码为字节数组并创建 35 //用字节分隔消息。读卡器作为每次发送的有效负载。 36 type Msg struct { 37 Code uint64 38 Size uint32 //Paylod的规模 39 Payload io.Reader 40 ReceivedAt time.Time 41 } 42 43 //解码将消息的rlp内容解析为 44 //给定值,必须是指针。 45 // 46 //解码规则见RLP包。 47 func (msg Msg) Decode(val interface{}) error { 48 s := rlp.NewStream(msg.Payload, uint64(msg.Size)) 49 if err := s.Decode(val); err != nil { 50 return newPeerError(errInvalidMsg, "(code %x) (size %d) %v", msg.Code, msg.Size, err) 51 } 52 return nil 53 } 54 55 func (msg Msg) String() string { 56 return fmt.Sprintf("msg #%v (%v bytes)", msg.Code, msg.Size) 57 } 58 59 //丢弃将剩余的有效载荷数据读取到黑洞中。 60 func (msg Msg) Discard() error { 61 _, err := io.Copy(ioutil.Discard, msg.Payload) 62 return err 63 } 64 65 type MsgReader interface { 66 ReadMsg() (Msg, error) 67 } 68 69 type MsgWriter interface { 70 //writemsg发送消息。它将一直阻塞到消息 71 //另一端消耗了有效载荷。 72 // 73 //请注意,消息只能发送一次,因为它们 74 //有效负载读卡器已排空。 75 WriteMsg(Msg) error 76 } 77 78 //msgreadwriter提供对编码消息的读写。 79 //实现应该确保readmsg和writemsg可以 80 //从多个goroutine同时调用。 81 type MsgReadWriter interface { 82 MsgReader 83 MsgWriter 84 } 85 86 //send用给定的代码编写一个rlp编码的消息。 87 //数据应编码为RLP列表。 88 func Send(w MsgWriter, msgcode uint64, data interface{}) error { 89 size, r, err := rlp.EncodeToReader(data) 90 if err != nil { 91 return err 92 } 93 return w.WriteMsg(Msg{Code: msgcode, Size: uint32(size), Payload: r}) 94 } 95 96 //senditems用给定的代码和数据元素编写一个rlp。 97 //对于以下电话: 98 // 99 //发送项(W、代码、E1、E2、E3) 100 // 101 //消息有效负载将是包含以下项目的RLP列表: 102 // 103 //[E1,E2,E3] 104 // 105 func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { 106 return Send(w, msgcode, elems) 107 } 108 109 //eofsignal用eof信号包裹读卡器。EOF通道是 110 //当包装的读卡器返回错误或计数字节时关闭 111 //已经看过了。 112 type eofSignal struct { 113 wrapped io.Reader 114 count uint32 //剩余字节数 115 eof chan<- struct{} 116 } 117 118 //注意:使用eofsignal检测消息有效负载时 119 //已被读取,对于零大小的邮件可能不调用读取。 120 func (r *eofSignal) Read(buf []byte) (int, error) { 121 if r.count == 0 { 122 if r.eof != nil { 123 r.eof <- struct{}{} 124 r.eof = nil 125 } 126 return 0, io.EOF 127 } 128 129 max := len(buf) 130 if int(r.count) < len(buf) { 131 max = int(r.count) 132 } 133 n, err := r.wrapped.Read(buf[:max]) 134 r.count -= uint32(n) 135 if (err != nil || r.count == 0) && r.eof != nil { 136 r.eof <- struct{}{} //告诉对等机消息已被消耗 137 r.eof = nil 138 } 139 return n, err 140 } 141 142 //msgpipe创建消息管道。一端读取匹配 143 //写在另一个上面。管道为全双工,两端 144 //实现msgreadwriter。 145 func MsgPipe() (*MsgPipeRW, *MsgPipeRW) { 146 var ( 147 c1, c2 = make(chan Msg), make(chan Msg) 148 closing = make(chan struct{}) 149 closed = new(int32) 150 rw1 = &MsgPipeRW{c1, c2, closing, closed} 151 rw2 = &MsgPipeRW{c2, c1, closing, closed} 152 ) 153 return rw1, rw2 154 } 155 156 //errPipeClosed在 157 //管道已关闭。 158 var ErrPipeClosed = errors.New("p2p: read or write on closed message pipe") 159 160 //msgpiperw是msgreadwriter管道的端点。 161 type MsgPipeRW struct { 162 w chan<- Msg 163 r <-chan Msg 164 closing chan struct{} 165 closed *int32 166 } 167 168 //writemsg在管道上发送消息。 169 //它会一直阻塞,直到接收器消耗了消息有效负载。 170 func (p *MsgPipeRW) WriteMsg(msg Msg) error { 171 if atomic.LoadInt32(p.closed) == 0 { 172 consumed := make(chan struct{}, 1) 173 msg.Payload = &eofSignal{msg.Payload, msg.Size, consumed} 174 select { 175 case p.w <- msg: 176 if msg.Size > 0 { 177 //等待有效负载读取或丢弃 178 select { 179 case <-consumed: 180 case <-p.closing: 181 } 182 } 183 return nil 184 case <-p.closing: 185 } 186 } 187 return ErrPipeClosed 188 } 189 190 //readmsg返回在管道另一端发送的消息。 191 func (p *MsgPipeRW) ReadMsg() (Msg, error) { 192 if atomic.LoadInt32(p.closed) == 0 { 193 select { 194 case msg := <-p.r: 195 return msg, nil 196 case <-p.closing: 197 } 198 } 199 return Msg{}, ErrPipeClosed 200 } 201 202 //关闭取消阻止两端所有挂起的readmsg和writemsg调用 203 //管子的它们将返回errpipeClosed。关闭也 204 //中断对消息有效负载的任何读取。 205 func (p *MsgPipeRW) Close() error { 206 if atomic.AddInt32(p.closed, 1) != 1 { 207 //其他人已经关门了 208 atomic.StoreInt32(p.closed, 1) //避免溢出 209 return nil 210 } 211 close(p.closing) 212 return nil 213 } 214 215 //expectmsg从r读取消息并验证其 216 //代码和编码的rlp内容与提供的值匹配。 217 //如果内容为零,则丢弃有效负载,不进行验证。 218 func ExpectMsg(r MsgReader, code uint64, content interface{}) error { 219 msg, err := r.ReadMsg() 220 if err != nil { 221 return err 222 } 223 if msg.Code != code { 224 return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) 225 } 226 if content == nil { 227 return msg.Discard() 228 } 229 contentEnc, err := rlp.EncodeToBytes(content) 230 if err != nil { 231 panic("content encode error: " + err.Error()) 232 } 233 if int(msg.Size) != len(contentEnc) { 234 return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) 235 } 236 actualContent, err := ioutil.ReadAll(msg.Payload) 237 if err != nil { 238 return err 239 } 240 if !bytes.Equal(actualContent, contentEnc) { 241 return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) 242 } 243 return nil 244 } 245 246 //msgeventer包装msgreadwriter并在每次发送消息时发送事件 247 //或收到 248 type msgEventer struct { 249 MsgReadWriter 250 251 feed *event.Feed 252 peerID discover.NodeID 253 Protocol string 254 } 255 256 //newmsgeventer返回一个msgeventer,它将消息事件发送到给定的 257 //喂养 258 func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer { 259 return &msgEventer{ 260 MsgReadWriter: rw, 261 feed: feed, 262 peerID: peerID, 263 Protocol: proto, 264 } 265 } 266 267 //readmsg从基础msgreadwriter读取消息并发出 268 //“收到消息”事件 269 func (ev *msgEventer) ReadMsg() (Msg, error) { 270 msg, err := ev.MsgReadWriter.ReadMsg() 271 if err != nil { 272 return msg, err 273 } 274 ev.feed.Send(&PeerEvent{ 275 Type: PeerEventTypeMsgRecv, 276 Peer: ev.peerID, 277 Protocol: ev.Protocol, 278 MsgCode: &msg.Code, 279 MsgSize: &msg.Size, 280 }) 281 return msg, nil 282 } 283 284 //writemsg将消息写入基础msgreadwriter并发出 285 //“消息已发送”事件 286 func (ev *msgEventer) WriteMsg(msg Msg) error { 287 err := ev.MsgReadWriter.WriteMsg(msg) 288 if err != nil { 289 return err 290 } 291 ev.feed.Send(&PeerEvent{ 292 Type: PeerEventTypeMsgSend, 293 Peer: ev.peerID, 294 Protocol: ev.Protocol, 295 MsgCode: &msg.Code, 296 MsgSize: &msg.Size, 297 }) 298 return nil 299 } 300 301 //close如果实现IO.closer,则关闭基础msgreadwriter。 302 //界面 303 func (ev *msgEventer) Close() error { 304 if v, ok := ev.MsgReadWriter.(io.Closer); ok { 305 return v.Close() 306 } 307 return nil 308 } 309