libp2p网络通信中还有一种方式就是PubSub模式,也称订阅发布的模式,官方给出了订阅发布模式的一个案例=> 聊天室

在此学习记录一下

官方代码地址:https://github.com/libp2p/go-libp2p/tree/master/examples/pubsub

一、效果演示

二、代码理解

2.1 总体框架

总的来说代码构成由这五个步骤:

1~2两步较为简单不再赘述, 下面几点分点描述

2.2 创建mDNS节点发现服务

注意,使用mDNS作为节点发现需要保证所有的节点在同一个局域网即节点发现的范围在同一个局域网下

// discoveryNotifee gets notified when we find a new peer via mDNS discovery
// 节点发现的通告结构体,继承Notifee
type discoveryNotifee struct {h host.Host
}// HandlePeerFound connects to peers discovered via mDNS. Once they're connected,
// the PubSub system will automatically start interacting with them if they also
// support PubSub.
// 继承函数,节点发现后的处理函数:自动链接节点
func (n *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) {fmt.Printf("discovered new peer %s\n", pi.ID.Pretty())err := n.h.Connect(context.Background(), pi)if err != nil {fmt.Printf("error connecting to peer %s: %s\n", pi.ID.Pretty(), err)}
}// setupDiscovery creates an mDNS discovery service and attaches it to the libp2p Host.
// This lets us automatically discover peers on the same LAN and connect to them.
func setupDiscovery(ctx context.Context, h host.Host) error {// setup mDNS discovery to find local peersdisc := mdns.NewMdnsService(h, DiscoveryServiceTag)n := discoveryNotifee{h: h}disc.RegisterNotifee(&n)return nil
}

2.3 加入聊天房

每个节点通过订阅房间的统一topic实现PubSub

1.聊天房数据结构

与一个topic一一对应,可以通过ChatRoom.Publish在topic中发布消息,并且接收所有的消息到Messages的channel中。

type ChatRoom struct {// Messages is a channel of messages received from other peers in the chat roomMessages chan *ChatMessagectx   context.Contextps    *pubsub.PubSubtopic *pubsub.Topicsub   *pubsub.SubscriptionroomName stringself     peer.IDnick     string
}// ChatMessage gets converted to/from JSON and sent in the body of pubsub messages.
type ChatMessage struct {Message    stringSenderID   stringSenderNick string
}func (cr *ChatRoom) Publish(message string) error {m := ChatMessage{Message:    message,SenderID:   cr.self.Pretty(),SenderNick: cr.nick,}msgBytes, err := json.Marshal(m)if err != nil {return err}return cr.topic.Publish(cr.ctx, msgBytes)
}

2.加入聊天房逻辑

分为三步,成功后返回一个新的ChatRoom实例

func JoinChatRoom(ctx context.Context, ps *pubsub.PubSub, selfID peer.ID, nickname string, roomName string) (*ChatRoom, error) {// join the pubsub topictopic, err := ps.Join(topicName(roomName))if err != nil {return nil, err}// and subscribe to itsub, err := topic.Subscribe()if err != nil {return nil, err}cr := &ChatRoom{ctx:      ctx,ps:       ps,topic:    topic,sub:      sub,self:     selfID,nick:     nickname,roomName: roomName,Messages: make(chan *ChatMessage, ChatRoomBufSize),}// start reading messages from the subscription in a loopgo cr.readLoop()return cr, nil
}

发布和订阅较为直观,下面是循环读取:

3.循环读取消息内容

循环读取内容,并将被容加入到消息channel中

// readLoop pulls messages from the pubsub topic and pushes them onto the Messages channel.
func (cr *ChatRoom) readLoop() {for {// Next returns the next message in our subscription// 找到下一个消息msg, err := cr.sub.Next(cr.ctx)if err != nil {close(cr.Messages)return}// only forward messages delivered by others// 只接收别人的消息if msg.ReceivedFrom == cr.self {continue}// 反序列化cm := new(ChatMessage)err = json.Unmarshal(msg.Data, cm)if err != nil {continue}// send valid messages onto the Messages channel// 把消息加入 Messages channelcr.Messages <- cm}
}

4.获取当前topic所有连接者

func (cr *ChatRoom) ListPeers() []peer.ID {// ListPeers returns a list of peers we are connected to in the given topic.return cr.ps.ListPeers(topicName(cr.roomName))
}

对于UI部分不是重点,会使用即可

总体来说案例使用较为简单,可以快速上手!

P2P网络编程-3-案例实践:PubSub相关推荐

  1. P2P网络编程-2-案例实践:P2P聊天应用

    文章目录 一.初代版本 1.1 简介 1.2 代码与解析 1.3 测试运行 二.节点发现 2.1 简介 2.2 代码与解析 2.3 测试运行 三.总结 3.1 libp2p节点发现构建流程 3.2 l ...

  2. Visual C++网络编程经典案例详解 第9章 实用播放器 数据读取与播放控制 识别数据文件信息

    识别数据文件信息主要是指对mp3数据格式识别 定义顺序代码如下 typedef struct mp3_struct //自定义mp3结构体 {char heade[3]; //tag字符标记char ...

  3. 史上最简单的spark教程第十三章-SparkSQL编程Java案例实践(终章)

    Spark-SQL的Java实践案例(五) 本章核心:JDBC 连接外部数据库,sparkSQL优化,故障监测 史上最简单的spark教程 所有代码示例地址:https://github.com/My ...

  4. C#网络编程的最佳实践

    网络框架的选择 C++语言里面有asio和libuv等网络库, 可以方便的进行各种高效编程. 但是C#里面, 情况不太一样, C#自带的网络API有多种. 例如: Socket TcpStream(同 ...

  5. 流式套接字:基于TCP协议的Socket网络编程(案例2)

    案例:在案例1的基础上实现一个服务器对应多个客户端(多线程),且获得每个客户端的IP. 线程代码: package com.yh.mySocket;import java.io.BufferedRea ...

  6. Visual C++网络编程经典案例详解 第8章 网络文件传输 使用api函数操作文件 创建文件 CreateFile原型

    使用mfc编程 处理使用CFile类操作文件 还可以使用api函数 有关文件操作的函数进行编程 用户可以使用函数Create()进行创建文件对象 HANDLE CreateFile{LPCTSTR l ...

  7. Visual C++网络编程经典案例详解 第5章 网页浏览器 CHtmlView类 查看源文件

    在菜单 查看源文件 的消息响应函数中实现完整的查看源文件功能 void CMainFrame::OnViewmenu() //查看源代码函数 {char sch[2048]={0};CFile fil ...

  8. Visual C++网络编程经典案例详解 第9章 实用播放器 多线程通信 线程间通信 根据播放列表音乐序号判断mp3播放顺序

    根据播放列表音乐序号判断mp3播放顺序 定义一个整形变量index int index=0; 在列表控件双击消息处理函数OnDblclkList2()中 将列表选择项的索引赋值给index void ...

  9. Visual C++网络编程经典案例详解 第9章 实用播放器 界面初始化 tab控件初始化 InsertItem()原型

    如果启动后 没有响应歌曲 则tab控件提示用户 播放器没有歌曲要添加歌曲 否则播放歌曲 添加成员变量对话框修改变量名称为m_tab 使用CTabCtrl类对象m_tab在TAB控件中添加属性页 Ins ...

最新文章

  1. ijkplayer iOS集成
  2. Numpy中数组间运算
  3. 选择排序的思想及其实现
  4. PAT甲级1020 Tree Traversals:[C++题解]树的遍历、由中序序列和后序序列递归建树
  5. 我犯了一个错误,您能指出吗?(结论)
  6. Java编程基础25——多线程上
  7. Android滑屏 mScrollX mScrollY scrollTo() scrollBy()
  8. elementUI 分页组件Bug ,为什么会 infinity ?
  9. Java使用递归实现全排列的代码
  10. Layer 2 DAO 基础协议 Metis 上线 Alpha 测试网
  11. php把数据表格数据,php怎样把数据添加到数据表
  12. 特征描述子(feature descriptor) —— HOG(方向梯度直方图)
  13. DOCKER镜像仓库地址
  14. ReportMachine通过嵌套表达式计算某个值。
  15. sql语句之多表查询
  16. 中国地区2012年第二季度 网络安全威胁报告
  17. WPF程序支持多国语言
  18. 1047: 字符图形3-平行四边形
  19. 在Python中输入汉字以及六个撇
  20. Android USB(OTG) 删除文件的探索过程

热门文章

  1. CP56time2a是什么格式?
  2. 基于CNN的海面舰船图像二分类
  3. 《Raytracing In One Weekend》学习笔记 Chapter 1、2、3、4、5、6、7、8、9、10、11、12、13
  4. Zabbix创建用户及告警媒介配置,配置qq邮箱告警配置/163(下)
  5. 月薪从11k到44k,一个普通程序员的三年涨薪之路...
  6. go每日新闻--2021-01-03
  7. SpringBoot笔记通俗易懂版
  8. 小车高速怎么收费标准_2018高速收费最新标准 跑长途的要看看
  9. 如何让简历中的“岗位业绩”打动HR?
  10. 软件测试是什么?我如果要学的话都该学哪些技能?