区块链基于WebSocket 构建P2P网络今天我们重点分析,在常见的java web开发中,比如boot框架开发的区块链系统,每个节点既是服务端又是客户端,因此不能引用spring-boot-starter-WebSocket 依赖,而是要引用Java-WebSocket 原生的依赖,以维持不同节点间的长连接。

1、pom引用:

     <dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.3.8</version></dependency>

2、服务端伪代码


import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;import javax.annotation.PostConstruct;import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.testng.util.Strings;/*** 基于springboot2.0的websocket服务端* * @author nandao**/
@Component
public class P2pPointServer {// 日志记录private Logger logger = LoggerFactory.getLogger(P2pPointServer.class);// 本机server的WebSocket端口// 多机测试时可改变该值private int port = 8001;// 所有连接到服务端的WebSocket缓存器private List<WebSocket> localSockets = new ArrayList<WebSocket>();public List<WebSocket> getLocalSockets() {return localSockets;}public void setLocalSockets(List<WebSocket> localSockets) {this.localSockets = localSockets;}/*** 初始化P2P Server端* @param Server端的端口号port*/@PostConstruct @Order(1)public void initServer() {/*** 初始化WebSocket的服务端 定义内部类对象socketServer,源于WebSocketServer; new* InetSocketAddress(port)是WebSocketServer构造器的参数 InetSocketAddress是(IP地址+端口号)类型,亦即端口地址类型*/final WebSocketServer socketServer = new WebSocketServer(new InetSocketAddress(port)) {/*** 重写5个事件方法,事件发生时触发对应的方法*/@Override// 创建连接成功时触发public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {sendMessage(webSocket, "服务端开打");// 当成功创建一个WebSocket连接时,将该链接加入连接池localSockets.add(webSocket);}@Override// 断开连接时候触发public void onClose(WebSocket webSocket, int i, String s, boolean b) {logger.info(webSocket.getRemoteSocketAddress() + "客户端与服务器断开连接!");// 当客户端断开连接时,WebSocket连接池删除该链接localSockets.remove(webSocket);}@Override// 收到客户端发来消息的时候触发public void onMessage(WebSocket webSocket, String msg) {logger.info("接收到客户端消息:" + msg);sendMessage(webSocket, "收到消息");}@Override// 连接发生错误的时候调用,紧接着触发onClose方法public void onError(WebSocket webSocket, Exception e) {logger.info(webSocket.getRemoteSocketAddress() + "客户端链接错误!");localSockets.remove(webSocket);}@Overridepublic void onStart() {logger.info("WebSocket Server端启动...");}};socketServer.start();logger.info("监听socketServer端口" + port);}/*** 向连接到本机的某客户端发送消息* * @param ws* @param message*/public void sendMessage(WebSocket ws, String message) {logger.info("发送给" + ws.getRemoteSocketAddress().getPort() + "的p2p消息是:" + message);ws.send(message);}/*** 向所有连接到本机的客户端广播消息* * @param message:待广播内容*/public void broatcast(String message) {if (localSockets.size() == 0 || Strings.isNullOrEmpty(message)) {return;}logger.info("Glad to say broatcast to clients being startted!");for (WebSocket socket : localSockets) {this.sendMessage(socket, message);}logger.info("Glad to say broatcast to clients has overred!");}
}

上述伪代码中,服务端调用initServer()方法初始化, 打开8001作为服务端口,其中重写了5个事件方法,事件发生时出发对应的方法,服务启动时调用onStart(),创建成功时触发onOpen(),断开时触发onClose(),收到客户端消息时调onMessage(),收到消息后向客户端返回“收到消息”的消息;连接发生错误时调用的方法onError(),onError调用完毕后触发onClose()方法。

此外,还有给所有连接到本机的客户端广播消息的方法broatcast()。

3、客户端伪代码

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;import javax.annotation.PostConstruct;import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.testng.util.Strings;/*** 基于springboot2.0的websocket客户端* * @author nandao**/
@Component
public class P2pPointClient {// 日志记录private Logger logger = LoggerFactory.getLogger(P2pPointClient.class);// P2P网络中的节既是Server端,又是Client端。作为Server运行在7001端口(P2pPointServer的port字段),同时作为Client通过ws://localhost:8001连接到服务端private String wsUrl = "ws://localhost:8001/";// 所有客户端WebSocket的连接池缓存private List<WebSocket> localSockets = new ArrayList<WebSocket>();public List<WebSocket> getLocalSockets() {return localSockets;}public void setLocalSockets(List<WebSocket> localSockets) {this.localSockets = localSockets;}/*** 连接到服务端*/@PostConstruct  //启动后执行@Order(2) //优先级public void connectPeer() {try {// 创建WebSocket的客户端final WebSocketClient socketClient = new WebSocketClient(new URI(wsUrl)) {@Overridepublic void onOpen(ServerHandshake serverHandshake) {sendMessage(this, "客户端打开");localSockets.add(this);}@Overridepublic void onMessage(String msg) {logger.info("收到服务端发送的消息:" + msg);}@Overridepublic void onClose(int i, String msg, boolean b) {logger.info("客户端关闭");localSockets.remove(this);}@Overridepublic void onError(Exception e) {logger.info("客户端报错");localSockets.remove(this);}};// 客户端 开始连接服务端socketClient.connect();} catch (URISyntaxException e) {logger.info("连接错误:" + e.getMessage());}}/*** 向服务端发送消息 当前WebSocket的远程Socket地址,就是服务器端* * @param ws:* @param message*/public void sendMessage(WebSocket ws, String message) {logger.info("发送给" + ws.getRemoteSocketAddress().getPort() + "的p2p消息:" + message);ws.send(message);}/*** 向所有连接过的服务端广播消息* * @param message:待广播的消息*/public void broatcast(String message) {if (localSockets.size() == 0 || Strings.isNullOrEmpty(message)) {return;}logger.info("Glad to say broatcast to servers being startted!");for (WebSocket socket : localSockets) {this.sendMessage(socket, message);}logger.info("Glad to say broatcast to servers has overred!");}
}

如上述伪代码,客户端用connectPeer()方法连接到服务端,在方法中客户端通过 ws://localhost:8001 连接到服务器。与服务端类似的地方有,重写五个事件方法。

为了保证connectPeer在服务启动时就能加载,用 @PostConstruct 标记使其加载bean的时候运行,并且只会被服务器执行一次,另外,为了保证服务端先与客户端加载,用 @Order(2) 标识了connectPeer方法。

同时还有,向所有连接过的服务端广播消息的方法broatcast()。

4、p2p网络执行流程如下:

1)当客户端执行connectPeer方法时,成功连接到服务端的onOpen方法时,服务端向客户端发送消息。

2)客户端接到服务端消息后,触发onMessage方法,打印日志;随后客户端onOpen方法执行 sendMessage(....),发送消息到服务端。

3)服务端接受到客户端消息,触发onMessage,随后调用sendMessage方法。

4)客户端接收到服务端消息,触发onMessage方法..........

总之,后面就是一个你来我往、循环往复的过程。

到此、基于WebSocket 构建P2P网络分享完毕,下篇分享区块链的共识算法,敬请期待!

区块链基于WebSocket 构建P2P网络相关推荐

  1. 区块链中Java基于WebSocket构建P2P网络

    一.pom依赖 <dependency><groupId>org.java-websocket</groupId><artifactId>Java-We ...

  2. 区块链简单实现之p2p网络多节点同步

    区块链简单实现之p2p网络多节点同步 将区块保存为json文件 节点 不确定性 区块里保存节点信息 并未向所有节点广播 简单模拟 广播的代码: 实现效果: 完整的代码: 承接上文:区块链的简单实现,我 ...

  3. 基于侧链的P2P网络设计

    p2p网络是一种在组网节点之间进行任务分配和工作负载的对等网络.节点之间地位相等.功能相同.无主次之分.没有中心节点,每一个节点既是服务的请求者又是服务的响应者.资源冗余存储,部分节点的故障不影响整体 ...

  4. 讯琥科技精彩亮相2021 MWC 上海:构建集成区块链技术的下一代移动网络

    ​2月23日-25日,2021 世界移动通信大会(MWC)上海站盛大召开,全球领先科技企业汇聚一堂,同台共秀技术实力.作为边缘计算和区块链领域的创新型企业,讯琥科技也展示了自己最新的产品和解决方案. ...

  5. 微软联手埃森哲打造基于区块链技术的数字化ID网络

    北京时间6月20日早间消息,埃森哲和微软正在联手打造一个使用区块链技术的数字化ID网络,这是由联合国提供支持的一个项目的部分内容,旨在向全球范围内没有官方凭证的11亿人提供合法的身份证明. 这两家公司 ...

  6. 区块链可扩展性技术:闪电网络

    哈尔滨工程大学 区块链讨论课 2018201125 陈晓龙 2018201204 魏金龙 参考博客/视频: https://www.bilibili.com/video/BV1yW411B7F5?t= ...

  7. 区块链101:什么是闪电网络?

    "闪电网络"被认为是目前正在开发的加密货币扩展的最有效的解决方案之一,它有效地在比特币之上创建了一层,使快速和廉价的交易能够满足比特币区块链的要求. 这一想法是由Thaddeus ...

  8. 初识区块链——用JS构建你自己的区块链

    初识区块链--用JS构建你自己的区块链 区块链太复杂,那我们就讲点简单的.用JS来构建你自己的区块链系统,寥寥几行代码就可以说明区块链的底层数据结构.POW挖矿思想和交易过程等.当然了,真实的场景远远 ...

  9. 基于NetworkX构建复杂网络的应用案例

    文章目录 基于NetworkX构建复杂网络的应用案例 本文内容 1.安装networkx以及校园拓扑图构建 1.1networkx安装 1.2校园拓扑结构绘制 2.复杂网络绘制,并指定筛选算法 2.1 ...

最新文章

  1. 2022-2028年中国木制拼板玩具市场调查研究报告
  2. 实例讲解UML建模分析与设计
  3. 1.5 matlab常量与变量
  4. 【原创】多线程应用中pthread库使用问题
  5. 技术分享:如何避免ajax重复请求?
  6. 将sublime text3添加到右键菜单中(可执行)
  7. Django web开发笔记
  8. 人设倒了扶起来:Lazarus 组织利用含木马的IDA Pro 攻击研究员
  9. java设计模式(五)--建造者模式(Builder)
  10. 【单片机毕业设计】【mcuclub-jj-035】基于单片机的保险柜的设计
  11. 图像分类以及经典的分类模型
  12. android简单悬浮窗源码,Android 悬浮窗的实现源码
  13. 原生JS实现中文简繁切换,引入即可整站变繁体
  14. 美国大学生解释为什么那么喜欢snapchat
  15. C#,深度好文,精致好码,文本对比(Text Compare)算法与源代码
  16. fMRI数据分析处理原理及方法fMRI数据分析处理原理及方法
  17. 写好CSS代码的70个专业建议-前端开发博客
  18. Ubuntu音乐播放器
  19. Nginx服务器概述
  20. Sql Server 2012完全彻底卸载教程

热门文章

  1. 大数据2--hive--hive介绍
  2. 微积分:如何理解方向导数与梯度?
  3. 数据结构中的算法,算法的定义与特征
  4. 话题挑战赛开团,千元奖金周边等你来拿
  5. 042-18 RMAN备份与恢复2
  6. 手机二维码扫码登录(Java源码及思路)
  7. (C语言)输入一行字符,将此字符串中最长的单词输出。
  8. 定义一个学生信息结构体,包含姓名,学号,语文成绩、数学成绩,和英语成绩,定义结构体数组存放不同学生的信息,可以在终端录入学生的信息,在基础上添加一个计算平均值和按照平均值排序以及删除指定学号的学生信息
  9. 申请专利流程及费用。
  10. FineReport JS实现分页预览改变鼠标悬停所在的行列的背景色