区块链-P2P(八)

2024-09-05 20:36
文章标签 区块 p2p

本文主要是介绍区块链-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(八)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140002

相关文章

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

数据库遇上知识图谱、区块链、深度学习

参考资料: https://zhuanlan.zhihu.com/p/33381916 https://www.zuozuovera.com/archives/1062/ 东南大学D&Intel Lab相关ppt 数据库的核心概念——表示、存取、查询 有了数据库是干什么,大概实现的逻辑,特点,才能引申出对当今这些新技术的对比、适应和发展。 目的:研究数据表示、存取数据模型:表示数据的模型,通

区块链技术介绍

一.概述 1.什么是区块链?   区块链是一种分布式数据库技术,它以链式数据结构的形式存储数据,每个数据块与前一个数据块相关联,形成了一个不断增长的数据链。每个数据块中包含了一定数量的交易信息或其他数据,这些数据经过加密和验证后被添加到区块链上。由于每个数据块都包含了前一个数据块的哈希值,因此任何尝试篡改数据的行为都会被迅速地检测出来。 2.区块链技术的起源   区块链的起源可以追溯到

孙宇晨:区块链领域的时代先锋,每一步引领未来趋势

​孙宇晨,这位在区块链领域崭露头角的青年企业家,凭借着敏锐的洞察力和坚定的决心,成为了数字经济时代的领航者。他的每一步,都走在技术创新的最前沿,推动着区块链技术的发展与应用,给全球经济带来了深远的影响。 从创业初期到现在,孙宇晨始终紧跟时代脉搏,勇敢地探索未知的领域。他对区块链技术的热情源于他对去中心化理念的深刻理解和认同。在区块链技术还处于初期发展阶段时,孙宇晨便看到了它将如何改变世界。区

【区块链 + 人才服务】链学汇教育区块链平台 | FISCO BCOS应用案例

链学汇教育区块链平台立足于教育行业区块链需求,结合真实应用场景和区块链技术,采取校企共建形式,构建基于产业发展及创新需求的实践教学和实训实习环境。目前已应用于东莞理工学院粤台产业科技学院,实现: 1. 通过“学、研、训、产”四位一体的应用人才培养模式,实践基地打造成为校企合作应用型人才培养示范基地; 2. 结合企业在区块链应用落地的丰富经验,将多种现实生活的场景与实训平台相结合,以丰富、趣味性

区块链ARC如何能让节点能够大规模处理交易数据

​​发表时间:2024年8月7日 TAAL技术主管Michael Böckli表示,TAAL公司一直在对ARC进行测试,并准备在今年年底全面发布。因TAAL在区块链交易处理方面具备深厚的专业知识,BSV区块链委托TAAL进行ARC开源参考落地方案的开发。 ARC是一个多层交易处理系统,能够追踪交易在BSV区块链上的整个生命周期。 除了遵循BSV区块链的开源指南和要求开发ARC的开源版

【区块链 + 人才服务】FISCO BCOS 区块链实训和管理平台 | FISCO BCOS应用案例

中博数科 FISCO BCOS 区块链实训和管理平台主要应用于区块链领域的教育和实训,目的是为学生、教师等用户 提供高效的区块链技术学习和实践体验,同时也为学校提供了一套完整的区块链解决方案。 该平台提供了一套完整的区块链课程体系,包括理论知识和实践项目,学生和开发者可以在平台上进行各种实验 和模拟,熟练掌握区块链的相关技术和应用,从而提供给企业有能力的区块链人才。同时,平台还提供了一套完整的区

[gtokentool]区块链技术的主要特征有哪些

区块链技术的主要特征 一、去中心化 去中心化是区块链最突出和本质的特征。区块链技术不依赖额外的第三方管理机构或硬件设施,没有中央控制。各个节点通过分布式的计费和存储实现信息的自校验、传输和管理。在区块链系统中,除了自成一体的区块链本身,每个节点都具有高度自治性,彼此之间可以自由链接,形成新的块-链数据,节点可以自由选择中心,中心也可以自由决定节点。因此,在没有中心节点的情况下实现了数据在整个网

Ignis公链探索生态建设新范式:产业区块链与GameFi双轨驱动

Ignis公链凭借其独特的技术架构,选择了产业区块链与GameFi这两个赛道作为生态建设的双轮驱动,逐步形成了一个多元化的Web3生态系统。 一、产业区块链的革新:Vessel Chain的成功案例 在产业区块链领域,Ignis公链通过推出Vessel Chain项目,展示了其在海运行业中的强大应用潜力。Vessel Chain是一个基于Ignis公链的创新项目,旨在提升海运行业的透明度和