区块链-P2P(八)
前言
P2P网络(Peer-to-Peer Network)是一种点对点的网络结构,它没有中心化的服务器或者管理者,所有节点都是平等的。在P2P网络中,每个节点都可以既是客户端也是服务端,这种网络结构的优点是去中心化、可扩展性强、抗攻击性强等。
1:P2P网络的优点
区块链 P2P 网络的优点有:
去中心化:没有中心化的服务器或者管理者,所有节点都是平等的。
高可用性:由于没有单点故障,所以整个系统非常稳定。
高安全性:由于每个节点都有完整的数据副本,所以即使有部分节点被攻击或者宕机,整个系统依然可以正常运行。
高效性:由于数据可以在多个节点之间共享和传输,所以整个系统非常高效。
2:分类
根据具体应用不同,可以把P2P分为以下这些类型[1]:
·提供文件和其它内容共享的P2P网络,例如Napster、Gnutella、eDonkey、emule、BitTorrent等;
·挖掘P2P对等计算能力和存储共享能力,例如SETI@home 、Avaki、Popular Power等;
·基于P2P方式的协同处理与服务共享平台,例如JXTA、Magi、Groove、.NET My Service等;
·即时通讯交流,包括ICQ、OICQ、Yahoo Messenger等;
·安全的P2P通讯与信息共享,例如Skype、Crowds、Onion Routing等。
3:区块链中的P2P网络
作为区块链的底层传输方式,P2P 技术帮助区块链成功实现了点对点的传播。比特币、以太坊等众多区块链项目都实现了属于自己的P2P网络协议,根据区块链的运行特点,我们可以总结出区块链客户端节点所组成p2p网络的一些需求:
1.节点可以任意地加入和离开网络;
2.每个节点所存储的数据(区块),在理想状态下是一致的(当然光凭p2p网络不能达到数据一致性,它只是提供了数据传输的逻辑通道,我们还需要共识算法来配合实现数据一致性);
3.在区块链网络中,查找数据时不需要向整个网络广播发送请求,正常情况下任意一个(或相邻几个)节点就可以提供完整的区块数据。
4:直接上代码
P2P打洞
UDP 打洞更容易点,网上一堆,不发了
TCP SERVER
#include <stdio.h> #include <signal.h> #include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> #ifdef _WIN32
#include <WinSock2.h>
#include<Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif#define MAXLINE 128
#define SERV_PORT 7119 //发生了致命错误,退出程序
void error_quit(const char *str)
{fprintf(stderr, "%s", str);//如果设置了错误号,就输入出错原因
#ifdef _WIN32if (errno != 0) {const int errmsglen = 255;char errmsg[errmsglen];strerror_s(errmsg, errmsglen, errno);fprintf(stderr, " : %s", errmsg);}
#elseif (errno != 0)fprintf(stderr, " : %s", strerror(errno));
#endifprintf("\n");exit(1);
}int main(void)
{int i, res, cur_port;
#ifdef _WIN32SOCKET connfd, firstfd, listenfd;WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2, 2);WSAStartup(wVersionRequested, &wsaData);
#elseint connfd, firstfd, listenfd;
#endifint count = 0;char str_ip[MAXLINE]; //缓存IP地址 char cur_inf[MAXLINE]; //当前的连接信息[IP+port] char first_inf[MAXLINE]; //第一个链接的信息[IP+port] char buffer[MAXLINE]; //临时发送缓冲区 socklen_t clilen;struct sockaddr_in cliaddr;struct sockaddr_in servaddr;//创建用于监听TCP协议套接字 listenfd = socket(AF_INET, SOCK_STREAM, 0);memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);//把socket和socket地址结构联系起来 res = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));if (-1 == res)error_quit("bind error");//开始监听端口 res = listen(listenfd, INADDR_ANY);if (-1 == res)error_quit("listen error");while (1){//接收来自客户端的连接 connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);if (-1 == connfd)error_quit("accept error");inet_ntop(AF_INET, (void*)&cliaddr.sin_addr, str_ip, sizeof(str_ip));count++;//对于第一个链接,将其的IP+port存储到first_inf中, //并和它建立长链接,然后向它发送字符串'first', if (count == 1){firstfd = connfd;cur_port = ntohs(cliaddr.sin_port);snprintf(first_inf, MAXLINE, "%s %d", str_ip, cur_port);#ifdef _WIN32strcpy_s(cur_inf, MAXLINE, "first\n");send(connfd, cur_inf, strlen(cur_inf) + 1, 0);
#elsestrcpy(cur_inf, "first\n");write(connfd, cur_inf, strlen(cur_inf) + 1);
#endif}//对于第二个链接,将其的IP+port发送给第一个链接, //将第一个链接的信息和他自身的port返回给它自己, //然后断开两个链接,并重置计数器 else if (count == 2){cur_port = ntohs(cliaddr.sin_port);snprintf(cur_inf, MAXLINE, "%s %d\n", str_ip, cur_port);snprintf(buffer, MAXLINE, "%s %d\n", first_inf, cur_port);#ifdef _WIN32send(connfd, buffer, strlen(buffer) + 1,0);send(firstfd, cur_inf, strlen(cur_inf) + 1,0);closesocket(connfd);closesocket(firstfd);
#elsewrite(connfd, buffer, strlen(buffer) + 1);write(firstfd, cur_inf, strlen(cur_inf) + 1);close(connfd);close(firstfd);
#endifcount = 0;}//如果程序运行到这里,那肯定是出错了 elseerror_quit("Bad required");}
#ifdef _WIN32WSACleanup();
#endifreturn 0;
}
/*
运行示例:
(第一个终端)
ubuntu@ubuntu ~/program/tcode $ gcc server.c -o server
ubuntu@ubuntu ~/program/tcode $ ./server &
[1] 4688
ubuntu@ubuntu ~/program/tcode $ gcc client.c -o client
ubuntu@ubuntu ~/program/tcode $ ./client localhost
Get: first
ff: 127.0.0.1 38052
send message: Hello, world
send message: Hello, world
send message: Hello, world
.................第二个终端:
ubuntu@ubuntu ~/program/tcode $ ./client localhost
Get: 127.0.0.1 38073 38074
connect error
recv message: Hello, world
recv message: Hello, world
recv message: Hello, world
*/
client
#include <stdio.h> #include <signal.h> #include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> #ifdef _WIN32
#include <WinSock2.h>
#include<Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif#define MAXLINE 128
#define SERV_PORT 7119 typedef struct
{char ip[32];int port;
}server;void error_quit(const char *str)
{fprintf(stderr, "%s", str);//如果设置了错误号,就输入出错原因
#ifdef _WIN32if (errno != 0) {const int errmsglen = 255;char errmsg[errmsglen];strerror_s(errmsg, errmsglen, errno);fprintf(stderr, " : %s", errmsg);}
#elseif (errno != 0)fprintf(stderr, " : %s", strerror(errno));
#endifprintf("\n");exit(1);
}int main(int argc, char **argv)
{int i, res, port;
#ifdef _WIN32SOCKET connfd, sockfd, listenfd;WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2, 2);WSAStartup(wVersionRequested, &wsaData);BOOL bReuseaddr = TRUE;
#elseint connfd, sockfd, listenfd;unsigned int value = 1;
#endifchar buffer[MAXLINE];socklen_t clilen;struct sockaddr_in servaddr, sockaddr, connaddr;server other;if (argc != 2)error_quit("Using: ./client <IP Address>");//创建用于链接(主服务器)的套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0);memset(&sockaddr, 0, sizeof(sockaddr));sockaddr.sin_family = AF_INET;sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);sockaddr.sin_port = htons(SERV_PORT);inet_pton(AF_INET, argv[1], &sockaddr.sin_addr);//设置端口可以被重用
#ifdef _WIN32setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&bReuseaddr, sizeof(BOOL));
#elsesetsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
#endif//连接主服务器 res = connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));if (res < 0)error_quit("connect error");//从主服务器中读取出信息
#ifdef _WIN32res = recv(sockfd, buffer, MAXLINE,0);
#elseres = read(sockfd, buffer, MAXLINE);
#endifif (res < 0)error_quit("read error");printf("Get: %s", buffer);//若服务器返回的是first,则证明是第一个客户端 if ('f' == buffer[0]){//从服务器中读取第二个客户端的IP+port
#ifdef _WIN32res = recv(sockfd, buffer, MAXLINE, 0);sscanf_s(buffer, "%s %d", other.ip,&other.port);
#elseres = read(sockfd, buffer, MAXLINE);sscanf(buffer, "%s %d", other.ip, &other.port);
#endifprintf("ff: %s %d\n", other.ip, other.port);//创建用于的套接字 connfd = socket(AF_INET, SOCK_STREAM, 0);memset(&connaddr, 0, sizeof(connaddr));connaddr.sin_family = AF_INET;connaddr.sin_addr.s_addr = htonl(INADDR_ANY);connaddr.sin_port = htons(other.port);inet_pton(AF_INET, other.ip, &connaddr.sin_addr);//尝试去连接第二个客户端,前几次可能会失败,因为穿透还没成功, //如果连接10次都失败,就证明穿透失败了(可能是硬件不支持) while (1){static int j = 1;res = connect(connfd, (struct sockaddr *)&connaddr, sizeof(connaddr));if (res == -1){if (j >= 10)error_quit("can't connect to the other client\n");printf("connect error, try again. %d\n", j++);
#ifdef _WIN32Sleep(1);
#elsesleep(1);
#endif}elsebreak;}
#ifdef _WIN32strcpy_s(buffer, MAXLINE, "Hello, world\n");
#elsestrcpy(buffer, "Hello, world\n");
#endif//连接成功后,每隔一秒钟向对方(客户端2)发送一句hello, world while (1){
#ifdef _WIN32res = send(connfd, buffer, strlen(buffer) + 1,0);
#elseres = write(connfd, buffer, strlen(buffer) + 1);
#endifif (res <= 0)error_quit("write error");printf("send message: %s", buffer);
#ifdef _WIN32Sleep(1);
#elsesleep(1);
#endif}}//第二个客户端的行为 else{//从主服务器返回的信息中取出客户端1的IP+port和自己公网映射后的port
#ifdef _WIN32sscanf_s(buffer, "%s %d %d", other.ip, &other.port, &port);
#elsesscanf(buffer, "%s %d %d", other.ip, &other.port, &port);
#endif//创建用于TCP协议的套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0);memset(&connaddr, 0, sizeof(connaddr));connaddr.sin_family = AF_INET;connaddr.sin_addr.s_addr = htonl(INADDR_ANY);connaddr.sin_port = htons(other.port);inet_pton(AF_INET, other.ip, &connaddr.sin_addr);//设置端口重用
#ifdef _WIN32BOOL bReuseaddr = TRUE;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&bReuseaddr, sizeof(BOOL));
#elsesetsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
#endif//尝试连接客户端1,肯定会失败,但它会在路由器上留下记录, //以帮忙客户端1成功穿透,连接上自己 res = connect(sockfd, (struct sockaddr *)&connaddr, sizeof(connaddr));if (res < 0)printf("connect error\n");//创建用于监听的套接字 listenfd = socket(AF_INET, SOCK_STREAM, 0);memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(port);//设置端口重用
#ifdef _WIN32setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&bReuseaddr, sizeof(BOOL));
#elsesetsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
#endif//把socket和socket地址结构联系起来 res = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));if (-1 == res)error_quit("bind error");//开始监听端口 res = listen(listenfd, INADDR_ANY);if (-1 == res)error_quit("listen error");while (1){//接收来自客户端1的连接 connfd = accept(listenfd, (struct sockaddr *)&sockaddr, &clilen);if (-1 == connfd)error_quit("accept error");while (1){//循环读取来自于客户端1的信息
#ifdef _WIN32res = recv(connfd, buffer, MAXLINE,0);
#elseres = read(connfd, buffer, MAXLINE);
#endifif (res <= 0)error_quit("read error");printf("recv message: %s", buffer);}
#ifdef _WIN32closesocket(connfd);
#elseclose(connfd);
#endif}}return 0;
}
golang的参考 github.com/ethereum/go-ethereum/
参考 https://blog.csdn.net/muxuen/article/details/137231514
5:运行结果(暂时手上没有公网服务器,请自行编译测试)
如果觉得有用,麻烦点个赞,加个收藏
相关文章:

区块链-P2P(八)
前言 P2P网络(Peer-to-Peer Network)是一种点对点的网络结构,它没有中心化的服务器或者管理者,所有节点都是平等的。在P2P网络中,每个节点都可以既是客户端也是服务端,这种网络结构的优点是去中心化、可扩展…...

数据库管理的利器Navicat —— 全面测评与热门产品推荐
在数据库管理领域,Navicat无疑是一款深受欢迎的软件。作为一个强大的数据库管理和开发工具,它支持多种数据库类型,包括MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL等。本文将全面测评Navicat的核心功能,同时推荐几款…...

如何让Google收录我的网站?
其实仅仅只是收录,只要在GSC提交网址,等个两三天,一般就能收录,但收录是否会掉,这篇内容收录了是否有展现,排名,就是另外一个课题了,如果不收录,除了说明你的网站有问题&…...

03 Flask-添加配置信息
回顾之前学习的内容 02 Flask-快速上手 Flask 中最简单的web应用组成 1. 导入核心库 Flask from flask import Flask2. 实例化 web应用 注意:不要漏了 app Flask(__name__) 中的 __name__ 表示:是从当前的py文件实例化 app Flask(__name__)3. 创…...

Codes 开源研发项目管理平台——敏捷测试管理创新解决方案
前言 Codes 是国内首款重新定义 SaaS 模式的开源项目管理平台,支持云端认证、本地部署、全部功能开放,并且对30人以下团队免费。它通过整合迭代、看板、度量和自动化等功能,简化测试协同工作,使敏捷测试更易于实施。并提供低成本的…...

耗时一个月,我做了一个网页视频编辑器
最近又肝了一个多月,终于把这个网页视频编辑器做好了,下面我来简单介绍一下如何使用 注意目前该功能还处在测试阶段,可能会有很多问题,后续我会不断修复 体验地址 app.zyjj.cc 界面介绍 整个剪辑界面包括4个区,左边是…...

uniapp 做一个查看图片的组件,图片可缩放移动
因为是手机端,所以需要触摸可移动,双指放大缩小。 首先在components里建个组件 查看图片使用 uni-popup 弹窗 要注意 transform的translate和scale属性在同一标签上不会一起生效 移动就根据触摸效果进行偏移图片 缩放就根据双指距离的变大变小进行缩…...

卡车配置一键启动无钥匙进入手机控车
卡车智能一键启动无钥匙进入手机控车,通过手机应用程序与汽车内置硬件、软件的无线通信,实现对汽车的远程控制。 卡车改装一键启动的步骤包括安装门把手的感应装置、拆卸仪表台和门板,取出内部的待接线束,并将一键启动…...
计算机网络基础概念 交换机、路由器、网关、TBOX
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、VLAN是什么?二 、交换机三、路由器四、网关五、TBOX六、问题1 、网关和交换机的区别2、网关和路由器的区别 总结 前言 工作有感而发࿰…...

labview禁用8080端口
需求背景 最近电脑上安装了labview全家桶,发现idea的8080端口项目启动报错,一直提示8080端口被占用。最简单的办法就是找到8080端口的服务,然后关闭这个服务。但是我不想这么做,我想把labview的web服务器的端口给修改了。 操作教程 1、cmd查看8080端口 2、windows进程 同…...
字符串的KMP算法详解及C/C++代码实现
1. 原由 紧接上文,我们知道了暴力匹配的算法在时间运行上的缺陷,假设字符串T的长度为n,字符串P的长度为m,则整个算法的时间复杂度为O( n * m ),而对于一个复杂的现实情况而言 n >> m >> 2 (即…...

2024年数学建模比赛题目及解题代码
目录 一、引言 1. 1竞赛背景介绍 1.1.1数学建模竞赛概述 1.1.2生产过程决策问题在竞赛中的重要性 1.2 解题前准备 1.2.2 工具与资源准备 1.2.3 心态调整与策略规划 二、问题理解与分析 三、模型构建与求解 3.1 模型选择与设计 3.1.1 根据问题特性选择合适的数学模型类…...

BERT 论文逐段精读【论文精读】
BERT: 近 3 年 NLP 最火 CV: 大数据集上的训练好的 NN 模型,提升 CV 任务的性能 —— ImageNet 的 CNN 模型 NLP: BERT 简化了 NLP 任务的训练,提升了 NLP 任务的性能 BERT 如何站在巨人的肩膀上的?使用了哪些 NLP 已有的技术和思想ÿ…...
在Flask中实现跨域请求(CORS)
在Flask中实现跨域请求(CORS,Cross-Origin Resource Sharing)主要涉及到对Flask应用的配置,以允许来自不同源的请求访问服务器上的资源。以下是在Flask中实现CORS的详细步骤和方法: 一、理解CORS CORS是一种机制&…...

在桌面商业分析应用程序中启用高级 Web UI
挑战 Mercur Business Control 应用程序在企业界,尤其是金融领域,拥有悠久的应用历史。它帮助企业处理、可视化和分析海量数据,从而做出明智的商业决策。 随着产品的不断演进和现代化,Mercur Solutions AB 为该应用创建了 Web 客…...

CentOS Stream 8 通过 Packstack 安装开源 OpenStack(V版)
1、环境规划以及网卡配置 controller IP:192.168.235.101 compute IP:192.168.235.102 控制节点 [rootluck ~]# cd /etc/sysconfig/network-scripts/ [rootluck network-scripts]# vi ifcfg-ens160 [rootluck network-scripts]# cat ifcfg-ens160 TYP…...
OpenSSL工具验证RSA证书
openssl x509 是一个用于处理 X.509 证书的命令行工具。常用的 openssl x509 命令: -in <file>:指定输入文件。-out <file>:指定输出文件。-noout:不输出证书信息。-text:以文本格式输出证书信息。-pubke…...

架构师白话分布式系统
对于分布式系统的定义,大致可以理解为如下的两个点 分布式系统从整体的体量来说,它内部是由很多的服务器、服务实例组成。所提供的用户服务是由一组相互独立运行的服务器来提供。对于用户来说,这个多服务器的系统就跟一个服务器一样,感觉不到每个单独的服务器实例的存在。从…...
C++ 中 vector 的常用功能介绍
在 C 中,vector 是一种常用的动态数组容器,提供了方便的自动扩展、内存管理以及各种便捷的操作方法。它是 C 标准模板库(STL)的一部分,适用于需要动态存储和管理大量元素的场景。 在本文中,我们将简要介绍…...

[QT] QT事件与事件重写
一.事件 事件(event)是由系统或者 Qt本身在不同的场景下发出的。当用户按下鼠标、敲下键盘,或者是窗口关闭等都会发出一个相应的事件。 一些事件在用户操作时发出(如鼠标/键盘事件); 另一些事件则是由系统自动发出(如计时器事件)。 Qt窗口中对于产生的一系列事件都…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...