【Linux】网络编程 - Socket套接字/基于UDP的网络通信
目录
一.套接字
1.什么是套接字/Socket套接字
2.套接字的分类
3.Socket套接字的常见API
二.网络字节序
1.什么是网络字节序
2.网络字节序和主机字节序的转换接口
三.IP地址形式上的转换
四.客户端的套接字不由程序员bind
1.为什么客户端套接字不能由程序员bind
2.OS是在什么时候给客户端bind了ip和port
五.基于UDP的网络通信
1.传输层协议UDP的基本特性
2.基于UDP协议的C/S网络通信
1).demo代码1
2.demo代码2 - mini聊天室
六.补充扩展
1.本地环回ip地址
2.云服务器不能绑定指定IP地址
3.服务器不推荐绑定确定IP
一.套接字
1.什么是套接字/Socket套接字
套接字是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序),各种进程使用这个相同的域互相之间用Internet协议簇来进行通信
Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API(应用程序编程接口),也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。 Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制
--- 摘自百度
Socket套接字属于应用层和传输层协议之间的一个抽象层, Socket套接字系列的API都是传输层来提供给我们使用的接口, 用来让我们在应用层中编写网络编程代码
在linux中, 一切皆文件, 网卡也是文件; socket套接字, 本质上, 就是一个文件描述符fd, 因为网络通信的本质也是使用文件来进行通信, 创建好套接字, 之后的网络通信, 想要发送/接收信息数据本质上都是在利用这个套接字文件来进行
2.套接字的分类
域间套接字 - 用于本主机内的进程间通信 - 基于套接字式的管道通信 - 原理类似于命名管道通信
原始套接字 - 用来编写一些工具 - 可以绕过运输层或网络层或其他层直接使用底层
网络套接字 - 用于网络通信 - 例如, socket套接字就是网络套接字
以上, 理论上应该是三套接口, 而linux"封装"了套接字类型, 将所有的接口进行了统一
其统一就体现在, sockaddr结构体类型
不管是sockaddr_in还是sockaddr_un都可以以强制类型转换的方式传给sockaddr, sockaddr依靠前两字节判断该sockaddr具体是sockaddr_in还是sockaddr_un还是其他套接字..., 补充: 为何不用void*? 因为网络接口的设计比C语言中void*更早, 所以那时还没有void*

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
以上三个头文件, 有一些网络编程中常用函数和sockaddr_in类型所需
sockaddr_in网络通信结构体类型:


总之, struct sockaddr_in内需要有:
哪种套接字(sin_family 类型: AF_INET or AF_UNIX or AF_LOCAL ...宏 --> int)
IP地址(sin_addr 类型: struct in_addr --> 内部只有一个成员s_addr 类型: in_addr_t --> uint32_t)
Port端口(sin_port 类型: in_port_t --> uint16_t)
剩下的均为填充字段(sin_zero不用管)
3.Socket套接字的常见API
#include <sys/types.h>
#include <sys/socket.h>
创建socket套接字, 即文件描述符(TCP/UDP)
本质: 创建一个指明运输层协议的文件供我们用来网络通信
int socket(int domain, int type, int protocol);
参数
1.domain: 表示套接字的域, 即套接字的类型, AF_UNIX域AF_LOCAL用于本地通信, AF_INET和AF_INET6用于网络通信(IPv4和IPv6), ...
2.type: 类型, 你想创建这个套接字的通信种类是什么, 面向流SOCK_STREAM?or面向数据报SOCK_DGRAM?or other?
3.protocol: 协议, 你想使用哪一种协议, 通常第一二个参数填好, 就代表第三个参数填好了, 如用AF_INET且SOCK_DGRAM也就代表使用传输层的UDP协议, 或AF_INET且SOCK_STREAM也就代表使用传输层的TCP协议, 通常如果采用默认传0即可
返回值: 文件描述符(在网络中就是套接字)
绑定端口号(TCP/UDP)
本质: 将用户设置的IP和port在内核中和我们当前进程及创建的socket套接字强关联
int bind(int socket, const struct sockaddr *addr, socklen_t address_len);
参数
1.socket: 我们创建的套接字
2.addr: 填充ip和port的结构体, 需要将struct sockaddr_in*强转成struct sockaddr*
3.address_len: addr结构体的长度(本质: uint32_t)
返回值: 成功返回0, 否则返回-1, 设置错误码errno
开始监听socket(TCP)
int listen(int socket, int backlog);
接收请求(TCP)
int accept(int socket, struct sockaddr *addr, socklen_t *address_len);
建立连接(TCP)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
本质: 从源ip主机, 即网络中, 接收数据
参数
sockfd: 创建并且绑定的套接字
buf: 读到buf中
len: buf大小
flags: 读取方式, 0代表阻塞式读取
src_addr: 源IP和port, 输出型参数
addrlen: 源IP和port的长度, 输入输出型参数, 输入: struct sockaddr_in的大小 输出: 实际读到的src_addr大小
注:!! src_addr与addrlen本质是要获取, 发送数据一端的ip&&port信息
返回值: 实际读取到的字节个数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
本质: 向目的ip主机, 即网络中, 发送数据
参数
sockfd: 创建并且绑定的套接字
buf: 发送数据的内容
len: 发送数据的长度
flags: 读取方式, 0代表阻塞式读取
dest_addr: 目的端的信息, ip port family...
addrlen: dest_addr的长度
二.网络字节序
1.什么是网络字节序
在计算机中, 内存存储字节有两种方式: 大端或小端
一台主机发送给另一台主机数据, 这两台机器在网络通信时并不知道对方是大端机还是小端机, 为了能够统一字节序, 便有了网络字节序这一概念
在TCP/IP协议族中, 网络字节序采用大端, 也就是不管发送什么数据, 都会按照大端(网络字节序)来发送/接收数据, 如果当前发送机是小端, 就要先将数据转成大端; 否则就忽略, 直接发送即可; 从网络中接收数据时也是同理
2.网络字节序和主机字节序的转换接口
包含头文件 <arpa/inet.h>
主机转网络
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
网络转主机
uint32_t ntohl(uint16_t netlong);
uint16_t ntohs(uint16_t netshort);
注: h - host代表主机; n - network代表网络; l - long代表长整型; s - short代表短整型
通常如果是port, 用short - uint16_t; 如果是IP, 用long - uint32_t
三.IP地址形式上的转换
为了让人更方便的看到ip地址, 通常输出/输入"点分十进制" 的ip地址, 每个.之间的数取值范围[0, 255]因为一个数只占1字节, 实际上计算机存储ip地址只需要4Byte就够了, 要是通过网络的传输的话还要把4字节ip转换为网络字节序, 这样一共有两步转换
1."点分十进制"字符串式ip --> 主机序列的4字节ip
2.主机序列的4字节ip --> 网络序列的4字节ip
以上两步可以通过同一接口进行转换
"点分十进制"字符串式ip --> 网络序列的4字节ip: in_addr_t inet_addr(const char* cp);
网络序列的4字节ip --> "点分十进制"字符串式ip: char *inet_ntoa(struct in_addr in);
四.客户端的套接字不由程序员bind
1.为什么客户端套接字不能由程序员bind
客户端client一定需要绑定ip和端口, 但是由用户的OS自动绑定的, 不能由程序员手动绑定, 因为程序员写的客户端client在未来是要交给用户, 并且让用户下载的, 程序员并不知道在用户的机器上的端口的使用情况, 由于1个端口只能绑定一个客户端, 所以这个绑定的过程要交给用户的机器OS自动进行
2.OS是在什么时候给客户端bind了ip和port
当客户端client首次发送信息给服务器的时候, 用户的OS会自动给用户客户端client绑定它的ip和port
五.基于UDP的网络通信
1.传输层协议UDP的基本特性
有连接
可靠传输
面向字节流
2.基于UDP协议的C/S网络通信
1).demo代码1
udp_server.hpp
#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <strings.h>
#include <unistd.h>
#include <cstring>#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>class udpServer
{
public:udpServer(const uint16_t port, const std::string ip = "") : _port(port), _ip(ip){}void Init(){// 1.创建Socket套接字_socket = socket(AF_INET, SOCK_DGRAM, 0);assert(_socket != -1);std::cout << "创建Socket套接字成功" << std::endl;// 2.绑定Socket套接字 -- ip和portstruct sockaddr_in sv;bzero(&sv, sizeof(sv));sv.sin_family = AF_INET;sv.sin_port = htons(_port);sv.sin_addr.s_addr = _ip == "" ? INADDR_ANY : inet_addr(_ip.c_str());socklen_t len = sizeof(sv);int ret = bind(_socket, (struct sockaddr *)&sv, len);assert(ret != -1);std::cout << "绑定Socket套接字成功" << std::endl;}void Start(){while (true){// 3.开始通信char buffer[1024];bzero(buffer, sizeof(buffer));// 3.1接收数据struct sockaddr_in cli;bzero(&cli, sizeof(cli));socklen_t len = sizeof(cli);ssize_t n = recvfrom(_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&cli, &len);if (n > 0){buffer[n] = '\0';// 3.2输出读取数据std::string cli_ip = inet_ntoa(cli.sin_addr);uint16_t cli_port = ntohs(cli.sin_port);printf("[%s:%d]# %s\n", cli_ip.c_str(), cli_port, buffer);// 4.原路发回sendto(_socket, buffer, strlen(buffer), 0, (struct sockaddr*)&cli, len);}else{std::cout << "本次未读到数据" << std::endl;}}}~udpServer(){close(_socket);}private:uint16_t _port; // 端口std::string _ip; // ipint _socket = -1; // Socket套接字
};
udp_server.cc
#include "udp_server.hpp"
#include <memory>static inline void Usage(char *&proc)
{std::cout << "correct way to use: " << proc << " port" << std::endl;
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);exit(-1);}uint16_t server_port = atoi(argv[1]); std::unique_ptr<udpServer> server(new udpServer(server_port));// 初始化服务器server->Init();// 启动服务器server->Start();return 0;
}
client.cc
#include "udp_server.hpp"
#include <memory>static inline void Usage(char *&proc)
{std::cout << "correct way to use: " << proc << " port" << std::endl;
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);exit(-1);}uint16_t server_port = atoi(argv[1]); std::unique_ptr<udpServer> server(new udpServer(server_port));// 初始化服务器server->Init();// 启动服务器server->Start();return 0;
}

2.demo代码2 - mini聊天室
udp_server.hpp
#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <strings.h>
#include <unistd.h>
#include <cstring>
#include <unordered_map>#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>class udpServer
{
public:udpServer(const uint16_t port, const std::string ip = "") : _port(port), _ip(ip){}void Init(){// 1.创建Socket套接字_socket = socket(AF_INET, SOCK_DGRAM, 0);assert(_socket != -1);std::cout << "创建Socket套接字成功" << std::endl;// 2.绑定Socket套接字 -- ip和portstruct sockaddr_in sv;bzero(&sv, sizeof(sv));sv.sin_family = AF_INET;sv.sin_port = htons(_port);sv.sin_addr.s_addr = _ip == "" ? INADDR_ANY : inet_addr(_ip.c_str());socklen_t len = sizeof(sv);int ret = bind(_socket, (struct sockaddr *)&sv, len);assert(ret != -1);std::cout << "绑定Socket套接字成功" << std::endl;}void Start(){while (true){// 3.开始通信char buffer[1024];bzero(buffer, sizeof(buffer));// 3.1接收数据struct sockaddr_in cli;bzero(&cli, sizeof(cli));socklen_t len = sizeof(cli);ssize_t n = recvfrom(_socket, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&cli, &len);char key[64];bzero(key, sizeof(key));if (n > 0){buffer[n] = '\0';// 3.2输出读取数据std::string cli_ip = inet_ntoa(cli.sin_addr);uint16_t cli_port = ntohs(cli.sin_port);printf("[%s:%d]# %s\n", cli_ip.c_str(), cli_port, buffer); // 给服务器打印// 注册发送数据的用户信息snprintf(key, sizeof(key), "%s-%u", cli_ip.c_str(), cli_port);_usrmessage[key] = cli;}// 向所有注册过的用户广播信息std::string message;message += key;message += "#";message += buffer;message += "\n";for (auto &e : _usrmessage){std::cout << "广播............" << std::endl;// 4.原路发回sendto(_socket, message.c_str(), message.size(), 0, (struct sockaddr *)&(e.second), sizeof(e.second));}}}~udpServer(){close(_socket);}private:uint16_t _port; // 端口std::string _ip; // ipint _socket = -1; // Socket套接字std::unordered_map<std::string, struct sockaddr_in> _usrmessage;
};
udp_server.cc
#include "udp_server.hpp"
#include <memory>static inline void Usage(char *&proc)
{std::cout << "correct way to use: " << proc << " port" << std::endl;
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);exit(-1);}uint16_t server_port = atoi(argv[1]); std::unique_ptr<udpServer> server(new udpServer(server_port));// 初始化服务器server->Init();// 启动服务器server->Start();return 0;
}
udp_client.hpp
#pragma once#include <iostream>
#include <cstdlib>
#include <strings.h>
#include <memory>
#include <unistd.h>
#include <thread>
#include <cstdio>
#include <sys/stat.h>
#include <fcntl.h>#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>class udpClient
{
private:static void Send(struct sockaddr_in sendUsr, int sock){while (true){// 2.发送数据std::string sendmessage;std::cout << "请输入: ";std::getline(std::cin, sendmessage);sendto(sock, sendmessage.c_str(), sendmessage.size(), 0, (struct sockaddr *)&sendUsr, sizeof(sendUsr));if (sendmessage == "quit"){std::cout << "the clientSend is closed" << std::endl;break;}}}static void Recv(int sock){std::string namedPath = "./JOKER.txt";umask(0);mkfifo(namedPath.c_str(), 0666);int fd = open(namedPath.c_str(), O_WRONLY | O_APPEND);while (true){// 3.接收server echochar buffer[1024];bzero(buffer, sizeof(buffer));ssize_t n = recv(sock, buffer, sizeof(buffer), 0);if (n > 0){buffer[n] = '\0';//std::cout << "Server Echo# " << buffer << std::endl;write(fd, buffer, sizeof(buffer));if (buffer == "quit"){std::cout << "the clientRecv is closed" << std::endl;break;}}}close(fd);}public:udpClient(std::string sip, uint16_t sport) : _sv_ip(sip), _sv_port(sport), _socket(-1){}void Init(){// 1.创建套接字_socket = socket(AF_INET, SOCK_DGRAM, 0);// 客户端由客户机OS自动绑定}void Start(){struct sockaddr_in sendUsr;bzero(&sendUsr, sizeof(sendUsr));sendUsr.sin_family = AF_INET;sendUsr.sin_addr.s_addr = inet_addr(_sv_ip.c_str());sendUsr.sin_port = htons(_sv_port);std::thread t_send(Send, sendUsr, _socket);std::thread t_recv(Recv, _socket);t_send.join();t_recv.join();}~udpClient(){close(_socket);}private:std::string _sv_ip;uint16_t _sv_port;int _socket;
};
udp_client.cc
#include "udp_client.hpp"static inline void Usage(char *&proc)
{std::cout << "correct way to use: " << proc << " ip port" << std::endl;
}int main(int argc, char* argv[])
{if(argc != 3){Usage(argv[0]);exit(-1);}std::string sv_ip = argv[1];uint16_t sv_port = atoi(argv[2]);std::unique_ptr<udpClient> client(new udpClient(sv_ip, sv_port));client->Init();client->Start();return 0;
}
六.补充扩展
1.本地环回ip地址
ip地址: 127.0.0.1 --> 本地环回
client和server发送数据指在本地协议栈中进行数据流动, 不会把我们的数据发送到网络中
只是把TCP/IP五层协议栈走一遍, 通常用来做本地网络服务器的测试
2.云服务器不能绑定指定IP地址
云服务器无法绑定公网IP地址
在云服务器中, 比如腾讯云, 他给我们提供的IP地址全部都是虚拟出来的, 不允许绑定这个确定的ip地址, 实际使用的不是这个IP地址, 所以我们无法在服务器进程上直接绑定这个地址
但其他人是可以通过这个虚拟出来的ip向云服务器互相网络通信的, 因为可以通过服务器进程绑定任意ip地址的方式来达到

3.服务器不推荐绑定确定IP
推荐服务器绑定"任意IP" -- 使用INADDR_ANY宏
INADDR_ANY宏, 本质是(in_addr_t)0x0000 0000 -- 让服务器在工作过程中可以从任意IP中获取数据 -- 即可以理解为有多少张网卡有多少IP都可以绑定上
因为服务器也许不止一张网卡, 也许有很多张网卡, 如果绑定了具体IP地址, 则服务器只能收到发送到这个IP地址的消息, 而如果使用任意IP的绑定方法, 则服务器就能收到发送到很多个IP地址的消息, 比如该服务器有3张网卡, 则客户端有可能分别向这三张网卡的IP发送数据, 服务器就都能收到了
当在机器上查看一个服务器进程或客户端进程的IP地址为0.0.0.0就说明为任意IP地址绑定
相关文章:
【Linux】网络编程 - Socket套接字/基于UDP的网络通信
目录 一.套接字 1.什么是套接字/Socket套接字 2.套接字的分类 3.Socket套接字的常见API 二.网络字节序 1.什么是网络字节序 2.网络字节序和主机字节序的转换接口 三.IP地址形式上的转换 四.客户端的套接字不由程序员bind 1.为什么客户端套接字不能由程序员bind 2.OS…...
流程引擎之Camunda简介
背景Camunda 是支持 BPMN(工作流和流程自动化)、CMMN(案例管理) 和 DMN(业务决策管理) java 框架。Camunda 基于Activiti5 保留了 PVM,其开发团队也是从 activiti 中分裂出来的。Camunda 来自拉…...
Mybatis笔记整理
1. 相关文档地址 中文文档 https://mybatis.org/mybatis-3/zh/index.htmlMybatis可以配置成适应多种环境,不过每个SqlSessionFactory实例只能选择一种环境。Mybatis默认事务管理器是JDBC,连接池:POOLEDMaven仓库:下载地址<dependency>…...
【react全家桶】面向组件编程
文章目录02 【面向组件编程】1.组件的使用1.1 函数式组件1.2 类式组件1.3 组合组件1.4 提取组件组件实例的三大属性 state props refs2.state2.1 基本使用2.2 setState()2.3 简化版本2.4 State 的更新可能是异步的2.5 异步更新解决方案2.6 数据是向下流动的3.props3.1 基本使用…...
Django框架之模型视图-使用 PostMan 对请求进行测试
使用 PostMan 对请求进行测试 PostMan 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件,可以直接去对我们写出来的路由和视图函数进行调试,作为后端程序员是必须要知道的一个工具。 安装方式1:去 Chrome 商店直接搜索 PostMan…...
(考研湖科大教书匠计算机网络)第五章传输层-第四节:TCP流量控制
获取pdf:密码7281专栏目录首页:【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一:流量控制概述二:流量控制举例三:拓展阅读(可不看)(1)TCP流量控制完整例子&a…...
使用Docker-Compose搭建Redis集群
1. 集群配置3主3从由于仅用于测试,故我这里只用1台服务器进行模拟redis列表2.编写redis.conf在server上创建一个目录用于存放redis集群部署文件。这里我放的路径为/root/redis-cluster 在/opt/docker/redis-cluster目录下创建redis-1,redis-2,redis-3,redis-4,redis…...
华为OD机试 -计算网络信号(Js)
计算网络信号 题目 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物 array[m][n] 的二维数组代表网格地图,array[i][j] = 0代表 i 行 j 列是空旷位置;array[i][j] = x(x 为正整数)代表 i 行 …...
【数据结构】————栈
文章目录前言栈是什么,栈的特点实现栈的基本操作栈的相关操作声明1.创建栈2.对栈进行初始化3.销毁栈4.判断栈是否为空5.压栈操作6.删除栈顶元素7.取出栈顶元素8.计算栈内存放多少个数据总结前言 本文主要讲述特殊的线性表——栈: 栈是什么,栈…...
从零编写linux0.11 - 第十一章 可执行文件
从零编写linux0.11 - 第十一章 可执行文件 编程环境:Ubuntu 20.04、gcc-9.4.0 代码仓库:https://gitee.com/AprilSloan/linux0.11-project linux0.11源码下载(不能直接编译,需进行修改) 本章目标 本章会加载并运行…...
Win10上通过nginx代理配置远程非445端口SMB
引言 家里架了一个SMB文件服务器,想要远程访问,开了445端口,但仅限某些特殊网络可以远程访问,其他网络全部拒绝445端口,因此网上找了很多将Win10的SMB指向别的端口的教程,但所有教程均使用环回网卡解决&am…...
Allegro如何快速清除多余的规则设置操作指导
Allegro如何快速清除多余的规则设置操作指导 在用Allegro做PCB设计的时候,会给PCB设置一些规则,在PCB设计完成之后,可能会有一些没有使用到的规则,如下图 Physical规则中的45OHM的规则是多余的 单独某个规则可以直接在规则管理器中删除,如果比较多可以用下面方法批量删除…...
ROS2 入门应用 引用自定义消息(Python)
ROS2 入门应用 引用自定义消息(Python)1. 查看自定义消息2. 修改话题发布3. 修改话题订阅4. 修改依赖关系5. 编译和运行1. 查看自定义消息 引用在《ROS2 入门应用 创建自定义接口》中自定义的消息Sphere.msg ros2 interface show tutorial_interfaces/…...
SmS-Activate一款好用的短信验证码接收工具
前言 有些国外应用在使用应用上的功能时需要注册账号,由于某种不可抗因素,我们的手机号一般不支持注册,接收不到信息验证码,于是我们可以使用SmS-Activate提供的服务,使用$实现我们的需求(大概一次验证1-5…...
SpringBoot+Elasticsearch按日期实现动态创建索引(分表)
😊 作者: 一恍过去💖 主页: https://blog.csdn.net/zhuocailing3390🎊 社区: Java技术栈交流🎉 主题: SpringBootElasticsearch按日期实现动态创建索引(分表)⏱️ 创作时间&…...
Terraform基础入门 (Infrastructure as Code)
文章目录前言介绍Terraform 术语Terraform 如何工作关于provider安装开启本地缓存demo1(dockernginx)demo2(dockerzookeeperkafka)参考资料前言 像写代码一样管理基础设施。 Terraform 使用较为高级的配置文件语法来描述基础设施,这个特性让你对配置文件进行版本化…...
Redis内存回收
Redis 内存回收 Redis之所以性能很强,最主要的原因是基于内存存储,然而单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能 可以通过修改配置文件来设置Redis的最大内存 maxmemory <bytes>当内存达到上限时,就…...
ROS2 入门应用 引用自定义消息(C++)
ROS2 入门应用 引用自定义消息(C)1. 查看自定义消息2. 修改话题发布3. 修改话题订阅4. 修改依赖关系5. 修改编译信息6. 编译和运行1. 查看自定义消息 引用在《ROS2 入门应用 创建自定义接口》中自定义的消息Sphere.msg ros2 interface show tutorial_i…...
Spring中的数据校验
数据校验基础 参考: Java Bean Validation 规范 Spring对Bean Validation的支持 Spring定义了一个接口org.springframework.validation.Validator,用于应用相关的对象的校验器。 这个接口完全从基础设施或者上下文中脱离的,这意味着它没有…...
python批量翻译excel表格中的英文
python批量翻译excel表格中的英文需求背景主要设计分析具体实现表格操作请求百度翻译api多线程控制台显示进度完整源码需求背景 女朋友的论文需要爬取YouTube视频热评,但爬下来的都是外文。 主要设计 读取一个表格文件,获取需要翻译的文本 使用百度翻译…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
