【计算机网络】Socket网络编程

💻文章目录
- 📄前言
- Socket编程基础
- 概念
- 工作原理
- Socket API介绍
- socket函数
- 绑定、监听函数
- accept、connect
- 接受/发送函数
- Socket API的应用
- Socket类与其派生类的设计
- 服务器与客户端的设计
- 使用
- 📓总结
📄前言
现今我们的日常生活当中,网络已经成为了必不可少的存在,大到覆盖全世界的互联网,小到身边的各种电器,可以说网络无处不在。我们作为一名程序员,如果对网络不甚了解,那么
注定会度过一个相对失败的一生,需要利用网络进行通信的应用正变得越来越多,企业对程序员网络知识的需求也越发变得重要,因此,学习网络一定会对你有所帮助。
Socket编程基础
概念
Socket 的中文名可以译为套接字、插座,就像它的直译插座一样,Socket 是两台机器网络通讯的端点,只要使用Socket就能连接两台机器,从而实现数据的传输、交换。
在介绍Socket是如何工作前,我们需要先了解一下网络的基本术语。
-
基础术语
-
IP地址:IP地址是设备在网络上的标识符,要进行网络通信就必须拥有一个IP地址
-
端口:端口的设计是为了让网络数据正确发送到应用程序,计算机通过IP+端口号来确保数据收发正确。
-
协议:协议是定义数据如何在网络传输的规则,Socket编程中会接触到的协议有UDP、TCP协议。
工作原理
正如上方所说Socket是网络通信的端点,Socket的工作原理是基于C—S模型,即必定会有客户端与服务端的存在。既然要通信,那么就一定会有协议的存在。socket 有面向字节流协议的SOCK_STREAM、面向数据报的 SOCK_DGRAM 和 直接将数据发往IP层的原始套接字 SOCK_RAW。
其实 SOCK_STREAM 与 SOCK_DGRAM 就已经可以完成99%的网络通讯设计,毕竟现在网络上主流的协议也就是UDP和TCP协议。虽然协议本身区别很大,但在应用层的使用上,大体还是差不多的。
-
服务器端的工作流程
-
创建套接字。
-
绑定地址。
-
接受数据。
-
发送数据。
-
-
客户端的工作流程
- 创建套接字
- 提前确定远端的地址、端口
- 发送数据
- 接受数据。
Socket API介绍
socket函数
socket函数是系统用于创建套接字描述符的接口,该函数会返回一个文件描述符,之后网络的通信便围绕着这个文件描述符进行。
#include <sys/socket.h>//函数原型
int socket(int domain, int type, int protocol);
// 返回值为文件描述符
int fd = socket(AF_INET, SOCK_STREAM, 0);
- 参数选项
- domain: 用于指定通信域,常用的选项为
AF_INET
(指定使用IPV4通信),AF_INET6
(指定IPV6通信),AF_UNIX
(指定本地进程间通信)。 - type: 用于指定socket的类型。常用的选项为
SOCK_STREAM
(提供可靠的流传输服务,也就是TCP),SOCK_DGRAM
(提供不可靠的数据报服务,也就是UDP)。 - protocl: 用于指定是否使用特殊协议,一般设为0。
- domain: 用于指定通信域,常用的选项为
绑定、监听函数
bind 函数用于让程序绑定一个固定的端口号,使套接字只从该端口号接受/发送数据,一般用于服务器显示绑定地址,客户端通过系统自动分配。listen 函数用于监听端口号,等待客户端的连接。
#include <sys/socket.h>int listen(int sockfd, int backlog); //成功返回0int bind(int sockfd, const struct sockaddr *addr, //成功返回0socklen_t addrlen);/* socketaddr是C语言历史缘由而留下来的结构体,因为当初C语言还不支持
void* 类型,所以设计出了sockaddr类型,以应对不同的选项。 *///以下是socketaddr家族
struct sockaddr { //基础类型sa_family_t sa_family; char sa_data[14];
}struct sockaddr_in { __uint8_t sin_len; //无特殊要求不会指定值sa_family_t sin_family; //设置协议家族(如AF_INET、AF_UNIX)in_port_t sin_port; //设置端口struct in_addr sin_addr; //设置IP地址char sin_zero[8];
};//socket_in6 用于IPV6设置。
- bind 参数选项
- sockfd: socket 文件描述符。
- addr: 绑定socket_addr。
- addrlen: 指定socket_addr的长度。
- listen 参数选项
- sockfd: 指定需要监听的套接字。
- backlog: 用于指定套接字中处于排队TCP连接数(还未得到处理),用于防止 SYN 泛洪攻击。
accept、connect
accept 和 connect 这两个函数,它们一般用于TCP协议,因为UDP是无连接的所以用不上(connect除外)。
accept 函数用于接受一个TCP连接,并返回它的套接字描述符,之后的读写则往该套接字描述符进行。注意,使用前需要先建立好监听状态。
connect 函数用于连接一个远端的服务器,成功则返回0.
#include <sys/types.h>
#include <sys/socket.h>int
accept(int socket, struct sockaddr *address, socklen_t *address_len);int //connect函数用于连接服务器
connect(int socket, const struct sockaddr *address, socklen_t address_len);
//UDP连接也可以使用connect函数,一般用于为UDP的套接字绑定一个固定的远端地址,从此该套接字就只能接受该地址的数据(过滤)。
-
accept 的参数选项
- socket: 指定需要接受数据的套接字接口
- address: 该结构用于接收连接方的协议地址。如果不想要远端的信息,可以设null。
- address_len: 用于指定address的长度。
-
connect 的参数选项
- socket: socket 文件描述符
- address: 指向存放目标服务器地址的信息。
- addlen: 指定addr结构体的长度。
接受/发送函数
unix like 系统中,UDP与TCP协议数据的收发所使用的函数有些许的差别,主要就是是否需要指定远端的地址、端口的差别,TCP方面因为已经通过 accpt 创建了一个包含远端信息的套接字,而UDP是无连接的,所以需要传入一个包含远端信息的sockaddr 结构体。
TCP协议所使用的接发函数:
#include <sys/socket.h>// recv send 参数都是一致的。
ssize_t recv(int sockfd, void buf, size_t len,int flags); ssize_t send(int sockfd, const void buf, size_t len, int flags);
- 参数选项:
- sockfd: 指定远端的套接字接口
- buf: 需要接受/发送的数据
- len: 数据的长度
- flags: 可提供额外的控制选项,如指定
阻塞等待(MSG_DONTWAIT)
。
UDP协议所使用的接收/发送函数:
ssize_t recvfrom(int sockfd, void buf, size_t len,int flags, struct sockaddr * src_addr, //可设为空,但如果要发送数据则要存储该结构体socklen_t * addrlen); ssize_t sendto(int sockfd, const void buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);// 额外所需要用的
uint16_t
htons(uint16_t hostshort); //将主机序列转为网络序列,网络数据使用大端传送unsigned long
inet_addr(const char *cp); //用于将字符串ip地址转为网络字节序的二进制形式
- 参数选项:
- sockfd: 指定需要接收/发送数据的套接字。
- buf: 数据所存放的内存
- flags: 发送的选项,与TCP一样
- addr: 如果需要发送数据,则需要在recvfrom指定中存储的sockadd结构体
- addrlen: sockaddr 的长度,如 sockaddr_in 。
Socket API的应用
介绍完了基本的函数信息,也该到实践的环节了,但如果只是简单写下函数的使用方法,也并没有什么实际意义,那么不如构建一个Socket编程的模版,这样以来使用 Socket 编程就不必再敲重复的代码,而且也能提高对设计模式的理解。
代码的大致样子:
Socket类与其派生类的设计
Socket 基类是TcpSocket、UdpSocket的抽象基类,用于提高代码的复用性。
#include <iostream>
#include <utility>
#include <arpa/inet.h>#define MAX_BUFFER_SIZE 1024struct RemoteData //用于获取远端数据
{
public:RemoteData() = default;explicit RemoteData(sockaddr_in& client, int fd = -1):_addr(client), _socket(fd){_data.resize(MAX_BUFFER_SIZE); }~RemoteData() = default;sockaddr_in _addr;std::string _data; // 改用 char buffer[];int _socket = -1;
};// 使用模版方法进行封装
class Socket
{
public:Socket(std::string ip, int port):_ip(std::move(ip)), _port(port){}void BuildServer() //用于服务器的构造{bool socket = CreateSocket();bool bindSocket = BindSocket();if(!(socket && bindSocket)){std::cerr << "socket build failed\n";return;}std::cout << "socket build success\n";}void BuildClient() // 用于客户端的构造{bool socket = CreateSocket();bool connectSocket = ConnectSocket();if(!(socket && connectSocket)){std::cerr << "socket build failed\n";return;}std::cout << "socket build success\n";}protected:virtual bool BindSocket() // 用于绑定套接字{if(::bind(_socket, (struct sockaddr*)&_addr, sizeof(_addr)) < 0)return false;return true;}virtual bool Accept(RemoteData* data) // 用于接受套接字{socklen_t len = sizeof (sockaddr_in);sockaddr_in* addr = &data->_addr;data->_socket = accept(_socket, (sockaddr*)addr, &len);if(data->_socket < 0){std::cerr << "accept failed " << strerror(errno) << std::endl;return false;}return true;}virtual bool ConnectSocket() // 用于连接套接字{if(::connect(_socket, (struct sockaddr*)&_addr, sizeof(_addr)) < 0)return false;return true;}virtual ~Socket() = default; // 基类继承需要把析构函数设为虚函数。virtual bool CreateSocket() = 0; // 创建套接字virtual bool RecvData(RemoteData*) = 0; // 接收数据virtual bool SendData(RemoteData*) = 0; // 发送数据
protected:int _socket=-1;int _port{};std::string _ip{};sockaddr_in _addr{};
};
TcpSocket 和 UdpSocket
TcpSocket 与 UdpSocket 就如其名,对应了TCP与UDP的socket编程设计。
class UdpSocket : public Socket
{ // UdpSocket如果使用connect函数,可以使用send、recv来代替sendto、recvfrom
public:UdpSocket(std::string ip, int port): Socket(std::move(ip), port) //初始化基类{}~UdpSocket() override = default;protected:bool CreateSocket() override{_addr.sin_family = AF_INET;_addr.sin_port = htons(_port); //将主机字节序列转为网络字节序列_addr.sin_addr.s_addr = inet_addr(_ip.c_str());_socket = socket(AF_INET, SOCK_DGRAM, 0);if(_socket < 0) return false; //错误处理return true;}bool RecvData(RemoteData* remoteData) override{char* buffer = remoteData->_data.data();socklen_t len = sizeof(sockaddr_in);sockaddr_in* client = &remoteData->_addr;ssize_t n = recvfrom(_socket, buffer, MAX_BUFFER_SIZE-1, 0, (struct sockaddr*)client, &len);if(n == 0){ std::cout << "client close\n";return false;}else if(n > 0){buffer[n] = '\0';std::cout << "recv data : " << buffer << std::endl;return true;}else{std::cerr << "recvfrom error\n";return false;}}bool ConnectSocket() override{return true;}bool SendData(RemoteData* data) override{char* buffer = data->_data.data();sockaddr_in* client = &data->_addr;ssize_t n = sendto(_socket, buffer, strlen(buffer), 0, (struct sockaddr*)client, sizeof(*client));if(n < 0){std::cerr << "sendto error: " << strerror(errno) << std::endl;return false;}return true;}
};class TcpSocket : public Socket
{
public:TcpSocket(std::string ip, int port): Socket(std::move(ip), port){}~TcpSocket() override = default;bool CreateSocket() override{ _addr.sin_family = AF_INET;_addr.sin_port = htons(_port);_addr.sin_addr.s_addr = inet_addr(_ip.c_str());_socket = socket(AF_INET, SOCK_STREAM, 0); //使用SOCK_STREAMif(_socket < 0) return false;return true;}bool BindSocket() override{if(::bind(_socket, (struct sockaddr*)&_addr, sizeof(_addr)) ){std::cerr << "bind failed\n";return false;}listen(_socket, 5); //TCP服务器需要监听端口return true;}bool RecvData(RemoteData* remoteData) override{int socket = remoteData->_socket;char* buffer = remoteData->_data.data();ssize_t n = recv(socket, buffer, MAX_BUFFER_SIZE-1, 0);if(n == 0){std::cout << "client close\n";return false;}else if(n > 0){buffer[n] = '\0';std::cout << "recv data : " << buffer << std::endl;return true;}else{std::cerr << "recv error\n";return false;}}bool SendData(RemoteData* data) override{int socket = data->_socket;char* buffer = data->_data.data();ssize_t n = send(socket, buffer, strlen(buffer), 0);if(n < 0){std::cerr << "send error\n";return false;}return true;}
};
服务器与客户端的设计
服务器设计
#include <memory>
#include <print>
#include "Socket.hpp"
//#include "ThreadPool.hpp" //不懂线程池的可以去看看我写的线程池博客class UdpServer : protected UdpSocket
{
public:UdpServer(int port, std::function<void(RemoteData*)> handler): UdpSocket("0.0.0.0", port), _handle(std::move(handler)){BuildServer(); //构建Socket}void Run(RemoteData* data){_handle(data); //业务处理函数SendData(data);}void start(){std::string msg;while (true){sockaddr_in client{};std::shared_ptr<RemoteData> data = std::make_shared<RemoteData>(RemoteData(client));if(!RecvData(data.get()))continue;
// ThreadPool::GetInstance()->enqueue([this, data]{ Run(data.get());});Run(data.get());}}private:std::function<void(RemoteData*)> _handle; //业务处理函数
};class TcpServer : TcpSocket // 注意:这个TCP协议需要进行粘包处理。
{
public:TcpServer(int port, std::function<void(RemoteData*)> handler): TcpSocket("0.0.0.0", port), _handle(std::move(handler)){BuildServer();}void ThreadRun(RemoteData* data){while (true){if(!RecvData(data)) break;_handle(data);if(!SendData(data)) break;}close(data->_socket);}void start(){std::string msg;while (true){sockaddr_in client{};std::shared_ptr<RemoteData> data = std::make_shared<RemoteData>(RemoteData(client));if(!Accept(data.get()))break;
// ThreadPool::GetInstance()->enqueue([this, data]{ ThreadRun(data.get());}); //最好使用多线程进行业务处理,否则将只能处理一条连接ThreadRun(data.get());}}
private:std::function<void(RemoteData*)> _handle;
};
客户端设计
class UdpClient : public UdpSocket
{
public:UdpClient(std::string ip, int port, std::function<void(RemoteData*)> func): UdpSocket(std::move(ip), port), _func(std::move(func)){BuildClient(); //}void start(){while (true){std::shared_ptr<RemoteData> data = std::make_shared<RemoteData>(RemoteData(_addr));_func(data.get());SendData(data.get());RecvData(data.get());}}private:std::function<void(RemoteData*)> _func;
};class TcpClient : public TcpSocket
{
public:TcpClient(std::string ip, int port, std::function<void(RemoteData*)> func): TcpSocket(std::move(ip), port), _func(std::move(func)){BuildClient();}void start(){while (true){std::shared_ptr<RemoteData> data = std::make_shared<RemoteData>(RemoteData(_addr, _socket));_func(data.get());SendData(data.get());RecvData(data.get());}}private:std::function<void(RemoteData*)> _func;
};
使用
//client.cpp
#include "Client.hpp"void handler(RemoteData* data)
{std::cout << "client: ";std::cin >> data->_data;
}int main()
{ // 使用本地环回进行通信UdpClient client("127.0.0.1", 8888, handler);client.start();return 0;
}//server.cpp
#include "Server.hpp"void handler(RemoteData* data)
{}int main() {ThreadPool* pool = ThreadPool::GetInstance(5);UdpServer server(8888, std::function<void(RemoteData*)>(handler));server.start();return 0;
}
📓总结
学习Socket编程只是迈入网络编程的第一步,计算机网络中还有TCP、UDP协议、IP协议等各种难关来等着我们来一一攻破。虽然你可能觉得学习Socket编程对学习TCP/IP协议这些没什么帮助,学校的老师也从来不会从代码开始攻坚计算机网络,但计算机网络就应该自顶至下,从应用层的应用开始学起。
📜博客主页:主页
📫我的专栏:C++
📱我的github:github

相关文章:

【计算机网络】Socket网络编程
💻文章目录 📄前言Socket编程基础概念工作原理 Socket API介绍socket函数绑定、监听函数accept、connect接受/发送函数 Socket API的应用Socket类与其派生类的设计服务器与客户端的设计使用 📓总结 📄前言 现今我们的日常生活当中…...

Ansible自动运维工具之playbook
目录 一.inventory主机清单 1.定义 2.变量 (1)主机变量 (2)组变量 (3)组嵌套 二.playbook基本内容 1.组成 (1)Tasks: 任务,即调用模块完成的某操作 ࿰…...

【启明智显技术分享】SSD201/SSD202D核心板UI界面开发全攻略:LVGL使用指南
提示:作为Espressif(乐鑫科技)大中华区合作伙伴及sigmastar(厦门星宸)VAD合作伙伴,我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考。同时也用心整理了乐鑫及星宸…...

数据可视化(九):Pandas北京租房数据分析——房源特征绘图、箱线图、动态可视化等高级操作
Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊! 喜欢我的博客的话,记得…...

ADOP带你了解:跳线与交叉电缆有何不同?
如果您想将设备连接到互联网,您可能想知道要使用的正确电缆。跳线和交叉电缆都是类型的以太网电缆,可帮助连接计算机、调制解调器、路由器和交换机等设备。那么,跳线和交叉电缆有什么区别呢?让我们讨论这两种类型的电缆࿰…...
Django 和 Spring Boot
标题 Django (Python)Django提供的组件Django 的处理逻辑 Spring Boot (Java)Spring Boot 的特点Spring Boot 的处理逻辑 MVC设计模式模型(Model)视图(View)控制器(Controller)逻辑处理过程 Django 和 Spri…...

上位机图像处理和嵌入式模块部署(树莓派4b的替代品)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 实话实说,树莓派4b的产品力还是比较优秀的,价格还算适中。但是和国产卡片电脑比起来,则逊色不少。功能差不多的…...

Springboot整合 Spring Cloud Gateway
1.Gateway介绍 1.是spring cloud官方推出的响应式的API网关框架,旨在为微服务架构提供一种简单有效的API路由的管理方式,并基于Filter的方式提供网关的基本功能,例如:安全认证,监控,限流等等。 2.功能特征…...

Rust开发工具有哪些?
目录 一、JetBrains公司的RustRover编辑 二、微软公司的Visual Studio Code 三、Rust编译工具 一、JetBrains公司的RustRover RustRover是由JetBrains开发的一款专为Rust开发量身定制的新兴IDE,目前还处于早期访问阶段。它支持Rust、Cargo、TOML、Web和数据库等…...

20240514基于深度学习的弹性超材料色散关系预测与结构逆设计
论文:Dispersion relation prediction and structure inverse design of elastic metamaterials via deep learning DOI:https://doi.org/10.1016/j.mtphys.2022.100616 1、摘要 精心设计的超材料结构给予前所未有的性能,保证了各种各样的具…...

SAP:FI 财务凭证行项目文本前台修改
一、问题描述 财务凭证行项目文本点击修改,但是前台有的行可以修改,有的行是灰色的不能修改,如下图所示,这个文本信息有误,必须修改怎么办? 二、思路分析 有的行可以修改,有的行不能修改&#x…...

【linux系统学习教程 Day02】网络安全之Linux系统学习教程,管道,文件内容统计,过滤排序,去重,目录介绍
1-4 管道 管道符号: | ,可以将前面指令的执行结果,作为后面指令的操作内容。 ## 比如过滤ip地址 ip addr | tail -4 | head -1 解释一下就是先执行 ip addr ,得到的结果当做 tail -4 的输入,意思就是查看ip addr 结果的后四行内容…...
Spring Cloud LoadBalancer 4.1.2
LoadBalancer位于Spring Cloud Commons 模块 Spring Cloud 提供了自己的客户端负载均衡器抽象和实现。对于负载均衡机制,添加了 ReactiveLoadBalancer 接口,并为其提供了基于Round-Robin和Random的实现。为了让实例从反应式中进行选择,使用了…...

使用Xshell工具连接ubuntu-方便快捷
使用Xshell连接ubuntu 在命令行输入 “sudo apt-get install openssh-server”安装openssh-server 开启 ssh-server,在命令行输入 “service ssh start”,然后输入密码即可...
leetcode22 括号生成-组合型回溯
题目 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 输入:n 3 输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 解析 func generateParenthesis(n int) …...

mac定时任务、自启动任务
https://quail.ink/mynotes/p/mac-startup-configuration-detailed-explanation <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.d…...

重磅 | 国家标准《网络安全技术 零信任参考体系架构》正式发布
根据2024年4月25日国家市场监督管理总局、国家标准化管理委员会发布的中华人民共和国国家标准公告(2024年第6号),其中易安联参编的国家标准GB/T 43696-2024《网络安全技术 零信任参考体系架构》正式发布,并于2024年11月1日正式施行…...

【C++】可变参数模板简单介绍
前言 可变参数模板是C11中的新特性,它能够让我们创建可以接收可变参数的函数模板和类模板,相比C98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数是一个巨大的改进,通过系统系统推演数据的类型…...

RabbitMQ--死信队列
目录 一、死信队列介绍 1.死信 2.死信的来源 2.1 TTL 2.2 死信的来源 3.死信队列 4.死信队列的用途 二、死信队列的实现 1.导入依赖 pom.xml 2.application.properties 3.配置类 4.生产者 5.业务消费者(正常消费者) 6.死信队列消费者 一、…...

微信小程序毕业设计-基于Java后端的微信小程序源码150套(附源码+数据库+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 🧡今天给大家分享150的微信小程序毕业设计,后台用Java开发,这些项目都经过精心挑选,涵盖了不同的实战主题和用例,可做毕业设…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...